> ## Documentation Index
> Fetch the complete documentation index at: https://docs.emergence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart: Hello Solution

> Stand up a minimal FastAPI service, package it as a Helm chart wrapping em-service, and deploy it to a local Kind cluster — under 30 minutes.

# Quickstart: Hello Solution

By the end of this tutorial you will have a FastAPI service running in a local Kubernetes cluster, packaged as a Helm chart that wraps the platform's `em-service` base chart, and reachable by `curl`. Total time: **30 minutes or less**. If it takes longer, that's a guide bug — please report via the 👎 thumbs at the bottom of this page.

<Info>
  This tutorial keeps every command and config snippet inline. Its one external dependency is the platform's `em-service` base chart, pulled from Emergence's **private** container registry during install — registry access is granted to the Emergence team and Solution/Agent design partners (you authenticate with `helm registry login` in the install step).
</Info>

## Prerequisites

Install these tools. Versions are floors, not pins — newer is fine.

| Tool    | Version | Purpose                        |
| ------- | ------- | ------------------------------ |
| Docker  | 24+     | Container runtime for Kind     |
| Kind    | 0.20+   | Local Kubernetes cluster       |
| kubectl | 1.28+   | Kubernetes CLI                 |
| Helm    | 3.13+   | Package manager for Kubernetes |
| uv      | 0.4+    | Python project manager         |

<Tabs>
  <Tab title="macOS">
    ```bash theme={null}
    brew install docker kind kubectl helm uv
    ```
  </Tab>

  <Tab title="Linux">
    ```bash theme={null}
    # Docker — follow distro-specific instructions at https://docs.docker.com/engine/install/

    # Kind
    curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
    chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind

    # kubectl
    curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
    chmod +x kubectl && sudo mv kubectl /usr/local/bin/

    # Helm
    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

    # uv
    curl -LsSf https://astral.sh/uv/install.sh | sh
    ```
  </Tab>
</Tabs>

## What you'll build

A solution called **`hello-solution`** with one component (`api`) that exposes:

* `GET /healthz` → `{"status":"ok"}` for k8s probes
* `GET /echo?msg=...` → echoes the message back

The image is built locally and loaded into Kind (no registry needed). The Helm chart wraps `em-service` v0.0.15 with `alias: api`, so you'll see how multi-component solutions extend (just add another alias).

## Steps

<Steps>
  <Step title="Create the project layout">
    Pick a working directory and scaffold these files:

    ```text theme={null}
    hello-solution/
    ├── packages/api/
    │   ├── pyproject.toml
    │   └── src/api/
    │       └── main.py
    ├── Dockerfile
    └── charts/hello-solution/
        ├── Chart.yaml
        └── values.yaml
    ```

    ```bash theme={null}
    mkdir -p hello-solution/packages/api/src/api hello-solution/charts/hello-solution
    cd hello-solution
    ```
  </Step>

  <Step title="Write the FastAPI app">
    <CodeGroup>
      ```python packages/api/src/api/main.py theme={null}
      from fastapi import FastAPI

      app = FastAPI(title="hello-solution")

      @app.get("/healthz")
      async def healthz() -> dict[str, str]:
          return {"status": "ok"}

      @app.get("/echo")
      async def echo(msg: str = "hi") -> dict[str, str]:
          return {"echo": msg}
      ```

      ```toml packages/api/pyproject.toml theme={null}
      [project]
      name = "hello-solution-api"
      version = "0.1.0"
      requires-python = ">=3.12"
      dependencies = [
        "fastapi>=0.110",
        "uvicorn[standard]>=0.30",
      ]

      [build-system]
      requires = ["hatchling"]
      build-backend = "hatchling.build"

      [tool.hatch.build.targets.wheel]
      packages = ["src/api"]
      ```
    </CodeGroup>
  </Step>

  <Step title="Write the Dockerfile">
    A multi-stage build keeps the runtime image small.

    ```dockerfile Dockerfile theme={null}
    FROM python:3.12-slim AS build
    WORKDIR /app
    RUN pip install --no-cache-dir uv
    COPY packages/api/pyproject.toml packages/api/pyproject.toml
    COPY packages/api/src packages/api/src
    RUN uv pip install --system --no-cache-dir ./packages/api

    FROM python:3.12-slim
    COPY --from=build /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
    COPY --from=build /usr/local/bin/uvicorn /usr/local/bin/uvicorn
    EXPOSE 8000
    CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"]
    ```
  </Step>

  <Step title="Write the Helm chart">
    The chart declares one `em-service` subchart, aliased as `api`. The platform's `em-service` (v0.0.15) handles Deployment, Service, probes, env vars — you only configure your image and ports. To add a worker later, you'd add another `em-service` entry with `alias: worker` and configure it under that alias key in `values.yaml`. See [em-service Chart](/deployment/helm/em-service) for the full values reference.

    <CodeGroup>
      ```yaml charts/hello-solution/Chart.yaml theme={null}
      apiVersion: v2
      name: hello-solution
      description: A minimal CRAFT solution
      type: application
      version: 0.1.0
      appVersion: "0.1.0"
      dependencies:
        - name: em-service
          alias: api
          version: 0.0.15        # latest tag published to the OCI registry
          repository: oci://ghcr.io/emergenceai/em-charts
      ```

      <Note>
        **Why `0.0.15` and not the latest source version?** The em-charts source
        `Chart.yaml` is on `0.0.16` (and an unrelated `0.1.0` ships for
        `em-charts-internal/em-service-internal`), but the OCI tag
        `ghcr.io/emergenceai/em-charts/em-service:0.0.15` is the most recent
        version actually published to the registry — `0.0.16` returns "not found"
        on `helm pull`. em-talk2data's own `Chart.yaml` pins `0.0.15` for the
        same reason. When em-charts publishes a newer tag, bump here.
      </Note>

      ```yaml charts/hello-solution/values.yaml theme={null}
      api:
        # em-service's fullname template defaults to the release name, which would
        # name every component "hello-solution" — collide if you add another alias.
        # Set fullnameOverride per component so resources are named "<solution>-<component>"
        # (this is what em-runtime itself does for governance/assets/utils).
        fullnameOverride: hello-solution-api
        image:
          repository: hello-solution-api
          tag: dev
          pullPolicy: IfNotPresent
        service:
          type: ClusterIP
          port: 8000
        env:
          LOG_LEVEL: "INFO"
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8000
          initialDelaySeconds: 2
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8000
          initialDelaySeconds: 5
      ```
    </CodeGroup>
  </Step>

  <Step title="Create a Kind cluster and load your image">
    ```bash theme={null}
    # Create cluster
    kind create cluster --name hello-solution

    # Build and load image
    docker build -t hello-solution-api:dev .
    kind load docker-image hello-solution-api:dev --name hello-solution
    ```

    `kind load docker-image` makes your local image available inside the cluster without a registry.
  </Step>

  <Step title="Install the chart">
    ```bash theme={null}
    # Authenticate to the private em-charts registry first (team / design-partner access)
    helm registry login ghcr.io
    helm dependency update ./charts/hello-solution
    helm upgrade --install hello-solution ./charts/hello-solution \
      --namespace em-hello-solution --create-namespace \
      --wait --timeout 5m
    ```

    First install pulls `em-service` from `ghcr.io/emergenceai/em-charts`, a **private** registry — `helm registry login ghcr.io` authenticates you (access is granted to the Emergence team and Solution/Agent design partners).
  </Step>

  <Step title="Smoke-test it">
    ```bash theme={null}
    kubectl port-forward -n em-hello-solution svc/hello-solution-api 8000:8000 &

    curl -s "http://localhost:8000/healthz" | jq .
    # {"status":"ok"}

    curl -s "http://localhost:8000/echo?msg=ship%20it" | jq .
    # {"echo":"ship it"}
    ```

    If both calls succeed, **you have shipped your first CRAFT solution**.
  </Step>

  <Step title="Tear down">
    ```bash theme={null}
    kill %1 2>/dev/null  # stop port-forward
    helm uninstall hello-solution -n em-hello-solution
    kubectl delete namespace em-hello-solution
    kind delete cluster --name hello-solution
    ```
  </Step>
</Steps>

## What you just did

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'lineColor': '#555555', 'fontFamily': 'sans-serif', 'edgeLabelBackground': '#ffffff'}}}%%
flowchart LR
    SRC["Source<br/>(packages/api/)"]
    DOCK["docker build<br/>hello-solution-api:dev"]
    LOAD["kind load<br/>docker-image"]
    HELM["helm install<br/>(em-service v0.0.15)"]
    NS[("Namespace<br/>em-hello-solution")]
    POD["Pod: api<br/>(port 8000)"]
    PF["kubectl<br/>port-forward"]
    CURL["curl /echo"]

    SRC --> DOCK --> LOAD --> HELM
    HELM --> NS
    NS --> POD
    POD --> PF --> CURL

    classDef sol fill:#56B4E9,stroke:#555555,color:#000
    classDef act fill:#E69F00,stroke:#555555,color:#000
    classDef store fill:#009E73,stroke:#555555,color:#000
    class SRC,POD sol
    class DOCK,LOAD,HELM,PF,CURL act
    class NS store
```

You wrapped a 25-line FastAPI app in a Helm chart that depends on the platform's `em-service` base chart, deployed it to a namespace named `em-<solution>` (the platform convention), and reached it via `port-forward`. You did not configure auth, secrets, storage, or LLMs yet — those are the next how-tos:

<CardGroup cols={2}>
  <Card title="Register a solution" icon="clipboard-check" href="/guides/solution-dev/register-a-solution">
    Make this naming + namespace pattern systematic.
  </Card>

  <Card title="Authenticate users" icon="shield-check" href="/guides/solution-dev/authenticate-users">
    Protect `/echo` with JWT validation.
  </Card>

  <Card title="Manage secrets" icon="key" href="/guides/solution-dev/manage-secrets">
    Wire a secret-backed env var into your chart.
  </Card>

  <Card title="Local development" icon="laptop-code" href="/guides/solution-dev/local-development">
    Loop faster with docker-compose + hot reload.
  </Card>
</CardGroup>
