# Technology Vision

A north star for how platform technologies fit together and where we invest.

---

## 📋 Overview

Forge uses multiple technologies that overlap in capability — TypeSpec and Aspire can both generate code, Terraform and Pulumi can both provision infrastructure, Azure DevOps and Aspire can both orchestrate deployments. This document defines the **role** each technology plays and the **boundaries** between them.

**Use this document to answer:**

- "Where does this technology fit in the platform?"
- "Should we use the vendor default or build our own?"
- "Is this new tool aligned with our direction?"

**This is NOT:**

- A migration plan with timelines or milestones
- A mandate to rewrite existing systems
- A replacement for the [Principles](principles.md) — it builds on them

> **🔗 See Also:** [Principles](principles.md) for the decision-making framework these choices are evaluated against.

---

## 🏗️ The Layered Model

The platform is composed of four layers plus a cross-cutting observability concern. Each layer has a clear responsibility and a clear boundary. The CLI sits above as the unified developer surface.

```text
┌─────────────────────────────────────────────────┐
│  Developer Surface (SAIF CLI)                   │  ← How developers interact
├─────────────────────────────────────────────────┤
│  Runner Layer (Azure DevOps / GitHub Actions)   │  ← When and where to run
├─────────────────────────────────────────────────┤
│  Orchestration Layer (Aspire)                   │  ← How things connect & deploy
├─────────────────────────────────────────────────┤
│  Contract Layer (TypeSpec)                      │  ← What the API looks like
└─────────────────────────────────────────────────┘
  Observability (OpenTelemetry)                     ← Universal signal layer
```

### Defaults First, Extend When Needed

Each layer relies on an extensible framework provided by a vendor. We use vendor defaults wherever they meet our requirements. We extend at the framework's designated extension points only when the default can't meet security, compliance, or operational needs.

| Layer          | Framework (Vendor) | Default Works?        | SAIF Extension                         |
| -------------- | ------------------ | --------------------- | -------------------------------------- |
| Contract       | TypeSpec compiler  | OpenAPI generation ✅  | Custom emitter for server code         |
| Contract       | TypeSpec compiler  | C# server stubs ❌     | Custom emitter for production patterns |
| Orchestration  | Aspire             | Local orchestration ✅ | —                                      |
| Orchestration  | Aspire             | Deployment targets ❌  | Custom hosting integrations            |
| Infrastructure | Pulumi / Terraform | Engine ✅              | Custom modules for SAIF patterns       |
| Observability  | OpenTelemetry      | ServiceDefaults ✅     | —                                      |
| Runner         | Azure DevOps       | Pipeline execution ✅  | Minimal YAML, invokes C# logic         |

The decision boundary is simple: *"Can the default meet our security, compliance, and operational requirements?"* If yes, use it. If no, extend at the framework's extension point. Never rebuild what the framework already does well.

---

## 📝 Contract Layer — TypeSpec

**Role:** Define the shape of APIs and data models using a purpose-built language.

### What the Framework Provides

TypeSpec gives us a compiler, type system, decorators, and an emitter plugin architecture. It's designed to be extended — emitters are the primary way TypeSpec produces output for different targets.

### What We Use As-Is

- **OpenAPI generation** — the `@typespec/openapi3` emitter produces spec-compliant OpenAPI documents. It's excellent and needs no customization.

### Where We Extend

- **Server code generation** — the `@typespec/http-server-csharp` emitter is the natural default. Microsoft recently rewrote it on the Alloy framework, signalling renewed investment. Before building anything custom, we evaluate whether its output quality now meets the enterprise bar and whether it can be extended (via the TypeSpec Emitter Framework) to express SAIF conventions: authorization wiring, controller augmentation model, service layer contracts, Mapperly-based mappers, and telemetry integration. If the default emitter's extension points are sufficient, we layer SAIF patterns on top. If not, we build a custom emitter on the same Alloy foundation.
- **Client SDK generation** — we use Kiota to generate clients from OpenAPI specs. The interchange format stays OpenAPI; TypeSpec never needs to be published or distributed to consumers. Kiota generates model classes per client namespace, so shared response shapes (notably error types) get duplicated once per generated client. We investigated this extensively — shared external `$ref` schemas, the `@typespec/http-client-csharp` emitter, custom generator plugins, and post-generation type unification all introduce more complexity than the problem warrants. No existing tool solves this cleanly, and building custom tooling around it is disproportionate effort. We accept the duplication as a cosmetic cost of generated code. For unified error handling, all Kiota-generated error types extend `ApiException` — consumers catch the common base class and read `.ResponseStatusCode` rather than dealing with per-client concrete types.

### Boundary

TypeSpec defines **what the API looks like** — endpoints, models, validation rules, authorization requirements. It does NOT define how services discover each other, where they deploy, or how they scale. That's Aspire's job.

---

## 🔌 Orchestration Layer — Aspire

**Role:** Define how services discover each other, what infrastructure they need, and how they deploy.

### What the Framework Provides

Aspire gives us the AppHost model, service discovery, a pipeline system (`aspire publish` / `aspire deploy`), and hosting integration extension points. The AppHost is the single source of truth for the application model across local development and production.

### What We Use As-Is

- **Local orchestration** — Aspire's AppHost, service discovery, and dashboard are proven and work perfectly for local development. No customization needed.
- **Pipeline model** — the `aspire publish` / `aspire deploy` entry points and step-based pipeline are used as designed.

### Where We Extend

- **Deployment targets** — the built-in targets (Azure Container Apps, App Service) deploy with generic patterns. Enterprise deployments need private networking, managed identity wiring, compliance tagging, multi-environment promotion, state management, and team-specific RBAC. We build **custom hosting integrations** (NuGet packages) that contribute Terraform or Pulumi steps to the Aspire pipeline.

### How the Pieces Fit

Aspire's deployment model explicitly separates two responsibilities:

- **CI/CD pipeline** (Azure DevOps) decides *when* jobs run, which approvals they require, and which credentials are available
- **Aspire pipeline** (AppHost) decides *what* the application means and which deployment steps are required

This separation means the CI/CD YAML stays thin — it invokes `aspire deploy` and lets the AppHost handle resource topology, ordering, and infrastructure composition.

### Boundary

Aspire defines **how things connect and deploy** — service topology, infrastructure composition, deployment orchestration. It does NOT define API contracts, business logic, or data models. That's TypeSpec's job (contracts) and application code (logic).

!!! note "Industry alignment"
    This layer maps to the **Platform Orchestrator** pattern described by [Humanitec](https://humanitec.com/blog/what-is-a-platform-orchestrator) and the **Integration & Delivery Plane** in the [platformengineering.org tooling landscape](https://platformengineering.org/platform-tooling). Aspire's AppHost acts as the workload specification + context resolver that Platform Orchestrators provide.

---

## 🖥️ Developer Surface — SAIF CLI

**Role:** The single interface through which developers interact with the platform. In lieu of an internal developer portal, the CLI plays that role — discovery, scaffolding, environment management, and AI agent integration from a unified command surface.

### What the CLI Provides

- **Scaffolding** (`saif new`) — create projects from platform templates (Golden Path)
- **Environment health** (`saif doctor`) — diagnose and remediate toolchain issues
- **Discovery** (`saif search`, `saif docs`, `saif app`) — find repos, documentation, and app registrations
- **Pipeline operations** (`saif pipeline`) — trigger and monitor CI/CD builds
- **Auth management** (`saif auth`) — generate and validate OAuth tokens
- **AI agent integration** (`saif agent`) — expose platform capabilities to coding agents via MCP

### Design Principles

- **Shell-first** — every agent has shell access; CLI commands are stateless, composable, and token-efficient
- **Structured output** (`--format json`) — humans get tables, agents get JSON; same commands, different presentation
- **Same commands, any actor** — AI agents use identical commands to humans; no separate "agent API"
- **Defaults first** — sensible defaults for interactive use, explicit flags for automation

### Boundary

The CLI is a **thin orchestration surface** — it calls into platform layers (Aspire, TypeSpec, Azure DevOps) rather than reimplementing their logic. It doesn't own business rules, deployment topology, or API contracts. It connects developers to the layers that do.

---

## 🧩 Platform Language — C\#

**Thesis:** The platform's own tooling is written in C# to reduce context-switching across platform components and enable shared infrastructure. Application code is developer's choice — we support C# and TypeScript.

### What Lives in C\#

- SAIF CLI and platform tooling
- Aspire hosting integrations and AppHost orchestration
- Custom TypeSpec emitters (server code generation)
- Infrastructure definitions (via Pulumi C# SDK)
- Build and deployment logic (invoked by thin pipeline runners)

### What Stays Outside C\#

- **Application code** — developers choose C# or TypeScript depending on their domain. The platform supports both.
- **Frontend UI** — TypeScript and React are the right tools for browser code.
- **Pipeline runner execution** — YAML defines *when* and *where* to run. Keeping it thin is the goal, not eliminating it.

---

## 🚀 Runner Layer — Pipelines

**Role:** Execute pre-defined logic — build, test, deploy.

### North Star

Pipelines become a thin execution shell. Logic lives in C# and is invoked via CLI commands (`dotnet`, `aspire`, `pulumi`). YAML defines *when* and *where* to run, not *what* to do.

### What This Means in Practice

- Pipeline templates shrink — they call `aspire deploy --environment production` rather than encoding resource topology in YAML steps
- Build logic moves into the application (MSBuild targets, Aspire pipeline steps)
- Test orchestration is a `dotnet test` invocation, not a complex multi-step YAML job
- Infrastructure provisioning is an Aspire pipeline step, not a separate Terraform stage with variable groups and manual approvals

### Why

Heavy pipeline YAML is difficult to test locally, requires specialized knowledge, and drifts from the application model. When deployment logic lives in the AppHost, developers can run and debug it on their machines before pushing to CI.

---

## 📡 Observability — OpenTelemetry

**Role:** Universal, vendor-agnostic telemetry (traces, metrics, logs).

### North Star

All services emit OpenTelemetry signals by default via Aspire ServiceDefaults. The Aspire dashboard provides local observability with full parity to production. The choice of observability vendor (Dynatrace today) is an infrastructure concern — applications emit signals, the platform routes them.

### What This Means

- Applications never reference a vendor SDK directly
- Switching vendors requires infrastructure configuration changes, not code changes
- Local development has the same observability experience as production (traces, metrics, logs visible in the Aspire dashboard)

---

## 📊 Today vs. North Star

This table summarizes where we are and where we're heading. It's a direction, not a deadline.

| Concern           | Today                                        | North Star                                                              |
| ----------------- | -------------------------------------------- | ----------------------------------------------------------------------- |
| Developer surface | SAIF CLI (scaffolding, search, doctor)       | CLI as internal developer portal (discovery, agents, self-service)      |
| API contracts     | TypeSpec → OpenAPI + default C# stubs        | TypeSpec → OpenAPI + custom emitter (production code)                   |
| Client generation | Kiota from OpenAPI                           | Kiota from OpenAPI (accepted; unified handling via `ApiException` base) |
| Local development | Aspire orchestration                         | Aspire orchestration (unchanged — proven)                               |
| Infrastructure    | Terraform (HCL) modules                      | C# via Pulumi, contributed as Aspire pipeline steps                     |
| Deployment        | Azure DevOps pipeline templates (heavy YAML) | `aspire deploy` + custom hosting integrations + thin runner             |
| Observability     | OpenTelemetry + Dynatrace                    | OpenTelemetry + Dynatrace (unchanged, vendor-swappable)                 |
| Build logic       | Pipeline YAML steps                          | C# tasks invoked by thin runner                                         |

---

## 🔑 Principle Alignment

This vision is evaluated against the same [Principles](principles.md) that guide all platform decisions:

| Principle                     | How This Vision Aligns                                                                                               |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Zero-Trust**                | Custom emitter bakes in authorization; custom hosting integrations enforce private networking and managed identities |
| **Proven Patterns**           | "Defaults first" is opinionated defaults; custom emitter generates code with patterns baked in                       |
| **Leverage Over Invention**   | Using frameworks' designed extension points because defaults aren't fit-for-purpose — not reinventing the framework  |
| **Speed-to-Value**            | Custom emitter generates deployment-ready code; hosting integrations enable `aspire deploy` to production            |
| **Team Autonomy**             | Self-service deploy via Aspire; CLI as portal — no pipeline YAML expertise needed                                    |
| **Local-First Orchestration** | Aspire local orchestration stays default — same model local and production                                           |
| **Platform as a Product**     | Layered model defines clear boundaries; CLI is the product surface                                                   |

---

## 📎 Industry Alignment

The layered model above is a **developer-facing application architecture** guide — it answers "how should I structure my app?" The industry platform engineering taxonomies ([CNCF Platforms White Paper](https://tag-app-delivery.cncf.io/whitepapers/platforms/), [platformengineering.org 5 Planes](https://platformengineering.org/platform-tooling), [internaldeveloperplatform.org Core Components](https://internaldeveloperplatform.org/core-components/)) answer a different question: "what should the platform offer?" They're complementary, not competing.

| Our Layer                   | Industry Term                                                                      | Source                                      |
| --------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- |
| **Developer Surface (CLI)** | **Internal Developer Portal** / Developer Control Plane                            | platformengineering.org 5 Planes, Backstage |
| **Contract (TypeSpec)**     | No standard equivalent — closest is "API-first design" or "Workload Specification" | General practice                            |
| **Orchestration (Aspire)**  | **Platform Orchestrator** / Infrastructure Orchestration + Environment Management  | Humanitec, internaldeveloperplatform.org    |
| **Runner (Azure DevOps)**   | **Integration & Delivery Plane**                                                   | platformengineering.org 5 Planes            |
| **Observability (OTel)**    | **Observability Plane**                                                            | platformengineering.org 5 Planes, CNCF      |
