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

# Annotation Reference

> Every Tensor9 BYOC annotation, the decision it records, its syntax, and an example.

> [!NOTE]
>
> Preview guidance. Review the decisions and proposed changes before applying them to your product.

An annotation records one decision about your stack that the Tensor9 compiler cannot make for you. It is a single comment line directly above the Terraform block it applies to. Terraform ignores it, so your own deployments do not change.

```terraform theme={null}
#@region(cloud='aws')
variable "aws_region" {
  type    = string
  default = "us-west-2"
}
```

New to annotations? Start with [Self-Service Onboarding](https://docs.tensor9.com/byoc/onboarding/overview.md), or [let an agent write them](https://docs.tensor9.com/byoc/onboarding/agent-skills.md).

## Syntax

```terraform theme={null}
#@name(key='value', other_key='value')
```

* **One annotation per comment line**, and nothing else on that line. Text after the closing parenthesis turns it into an ordinary comment that the compiler ignores. `//@name(...)` also works.
* **Parentheses are required**, even with no arguments: `#@elide()`, not `#@elide`.
* **Place it directly above** a `resource`, `data`, `variable`, `output` or `module` block, or above a single attribute inside `locals { }`. Ordinary comments may sit between the annotation and the block. Several annotations may stack above one block.
* **Arguments are `key='value'` pairs** separated by commas. Quote every value, numbers and booleans included (`max_size='32'`, `required='false'`). Single or double quotes both work; a value cannot contain its own quote character.
* **Annotations work in module files too.** Annotate the block where it is declared, whether that is your root module or a module it calls.
* **Use only the names on this page.** An unknown name fails the compile with an error naming it.

## The decisions most stacks make

| Annotation | Goes on | The decision |
| - | - | - |
| [`#@vanity_domain_root()`](#vanity_domain_root) | `string` variable | Which variable holds the domain an install serves |
| [`#@vanity_domain_provided()`](#vanity_domain_provided) | `bool` variable | Whether the stack should use an existing DNS zone instead of creating one |
| [`#@region(...)`](#region) | variable | Which variable follows the customer's region |
| [`#@project(...)`](#project) | variable | Which variable follows the customer's Google Cloud project |
| [`#@namespace(...)`](#namespace) | `string` variable | Which names must be unique per install, and how long the prefix may be |
| [`#@secret(...)`](#secret) | secret or parameter block | Who supplies each secret on an install |
| [`#@ingress(...)`](#ingress) | internet-facing resource | Which endpoints must stay public, or may be removed |
| [`#@elide()`](#elide) | any block | Which parts of your stack only your own environments need |

***

### vanity\_domain\_root

**Decision:** which variable holds the domain an install serves. Each install serves its own domain, either a subdomain Tensor9 assigns or a domain your customer brings. The compiler sets the default of the annotated `string` variable to that domain.

Annotate one variable per stack, and derive every host the install exposes (API, web, admin) from it. A host variable that does not derive from it keeps your value on every install.

Oumi example (`terraform/variables.tf`, `domain_name`):

```terraform theme={null}
#@vanity_domain_root()
variable "domain_name" {
  description = "Domain the application is served from"
  type        = string
}
```

### vanity\_domain\_provided

**Decision:** whether the stack looks up an existing DNS zone rather than creating one. On an install, the zone for the install's domain already exists before your stack runs. The compiler sets the annotated `bool` variable to `true` on installs that have that zone.

Use it when your stack already has a switch between creating the zone and looking it up.

For a public AWS zone in the root module, the compiler automatically replaces creation with a lookup when its name is exactly the variable annotated `#@vanity_domain_root()`, it has no `count`, `for_each` or `vpc`, and the install has a pre-created vanity zone. Original Oumi's `aws_route53_zone.main` matches this case once `domain_name` is annotated. Leave that source zone unchanged; no new switch is needed. Other zone shapes need review before adding a switch or changing DNS behavior.

```terraform theme={null}
#@vanity_domain_provided()
variable "hosted_zone_provided" {
  type    = bool
  default = false
}

resource "aws_route53_zone" "main" {
  count = var.hosted_zone_provided ? 0 : 1
  name  = var.domain_name
}

data "aws_route53_zone" "main" {
  count = var.hosted_zone_provided ? 1 : 0
  name  = var.domain_name
}
```

`#@vanity_domain_zone_name()` is the `string` counterpart: the compiler sets the variable to the zone's name as the DNS provider knows it. Use it when your stack looks a zone up by name, such as `data "google_dns_managed_zone"`.

### region

**Decision:** which variable should follow the region your customer installs into. The compiler sets the annotated variable's default to the install's region.

`cloud` (required) is `'aws'`, `'gcp'` or `'azure'` and names your stack's cloud. An annotation for a different cloud than the one being compiled is skipped with a warning. Provider aliases pinned to a literal region are not a region variable; leave them unannotated.

Oumi example (`terraform/variables.tf`, `aws_region`):

```terraform theme={null}
#@region(cloud='aws')
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-west-2"
}
```

### project

**Decision:** which variable holds the Google Cloud project your resources go into. The compiler sets the annotated variable's default to your customer's project. An unannotated project variable keeps your value, whatever it is called.

`cloud` (optional) is `'gcp'`.

```terraform theme={null}
#@project(cloud='gcp')
variable "project_id" {
  type = string
}
```

### namespace

**Decision:** which names must be unique per install, and how long a prefix they can afford. Two installs can share one account or project, so a name built only from your own values collides. The compiler sets the annotated `string` variable to a short prefix that is deterministic and unique per install.

* `max_size` (required): `'16'`, `'32'` or `'64'`, the maximum prefix length. Choose it from the tightest name limit you prefix (S3 bucket names allow 63 characters).
* `delimiter` (optional): included before the prefix is shortened to `max_size`. Defaults to empty. The shortened prefix may not end with that delimiter; check the compiled name rather than assuming a trailing separator.

Keep the default `""` so existing names are unchanged, then prefix each agreed name that must be unique. Adding the variable and prefixes is a source edit requiring your review; the annotation alone does not add them. See [Parameterization](https://docs.tensor9.com/byoc/origin-stack/terraform.md#parameterization) for which names need it.

Oumi proposal (`terraform/variables.tf` and `terraform/alb.tf`):

```terraform theme={null}
#@namespace(max_size='16', delimiter='-')
variable "namespace" {
  type    = string
  default = ""
}

resource "aws_s3_bucket" "alb_access_logs" {
  bucket = "${var.namespace}oumi-${var.environment}-alb-access-logs"
}
```

The same Oumi proposal prefixes `default_storage` and `temporal_backups`. Confirm the three bucket choices and the 16-character limit before editing. Check each complete compiled bucket name, including the configured environment string, against S3's 63-character limit. This example does not establish that the vendor approved the proposal or that every other Oumi resource name is ready for concurrent installs.

### secret

**Decision:** who supplies each secret on an install. Annotate `aws_secretsmanager_secret` and `aws_ssm_parameter` blocks, resources or data sources. Do not annotate `*_secret_version` blocks.

| Argument | Meaning |
| - | - |
| `ownership` | `'buyer'`: your customer enters the value while setting up the install, and you never see it. `'vendor'`: you supply the value and Tensor9 copies it into the install. `'platform'`: the stack or the cloud provider creates the value itself, for example a database's managed master password. |
| `displayName` | The label your customer sees. For `'buyer'` secrets. |
| `description` | Help text your customer sees. For `'buyer'` secrets. |
| `required` | `'true'` (default) or `'false'` when your customer may leave it blank, for example an optional integration. |
| `name` | The secret's name, when the block's own `name` is an expression rather than a literal string. |

Annotate every secret so each choice is explicit. A secret whose value your stack writes itself, for example from `random_password`, needs no annotation.

Oumi example (`terraform/cognito.tf`, Google sign-in):

```terraform theme={null}
#@secret(ownership='buyer', displayName='Google OAuth client secret', description='Client secret of the Google OAuth app used for sign-in', required='false', name='client-secret/google')
data "aws_secretsmanager_secret" "google_client_secret" {
  name = "${var.environment}/client-secret/google"
}
```

See [Secrets](https://docs.tensor9.com/byoc/fundamentals/secrets.md) for how each ownership model behaves at install time.

**When your plan must read a secret.** Customer secrets are sealed so that your Terraform plan never contains their values. If your stack's structure depends on a secret's value, for example it drives a `count` or `for_each`, mark that block with `#@secret_unsafely_disclosed`. That block is left unsealed, and the compile report tells your customer which value is shared with you and why. Every other secret stays sealed.

* `reason` (required): why your stack must read the value. Your customer sees it.
* `attrs` (optional): comma-separated attributes to leave unsealed. Defaults to every sensitive attribute of the block.

```terraform theme={null}
#@secret_unsafely_disclosed(reason='the stack decides which parameters exist from this configuration')
resource "aws_ssm_parameter" "config" {
  name  = "/myapp/config"
  type  = "SecureString"
  value = var.config_json
}
```

### ingress

**Decision:** which internet-facing endpoints are exceptions to your customer's ingress choice. Your customer may restrict public access to an install (see [Ingress Control](https://docs.tensor9.com/byoc/customizations/ingress.md)). Unannotated endpoints follow that choice. Annotate only the exceptions, on resources such as `aws_lb`, `kubernetes_ingress_v1` or `aws_cloudfront_distribution`.

* `posture='public_required'`: this endpoint stays public, for example a receiver for third-party webhooks.
* `elidable='true'`: this resource may be removed when ingress is not public, for example a CDN in front of a single-page app.
* `reason` (required with either): shown to your customer so they know what stays public and why.

Never set both `posture` and `elidable` on one resource.

```terraform theme={null}
#@ingress(posture='public_required', reason='payment provider webhooks')
resource "aws_lb" "webhooks" {
  name               = "${var.namespace}webhooks"
  load_balancer_type = "application"
  subnets            = var.public_subnet_ids
}
```

### elide

**Decision:** which blocks only your own environments need. The compiler removes an elided block from every install. Use it for machinery Tensor9 replaces or that has no place in a customer's environment: CI runners, self-signed certificate modules, operator-only tooling.

References to an elided block fail the compile, so make sure nothing else in the install depends on it.

```terraform theme={null}
#@elide()
module "ci_runner" {
  source = "./modules/ci-runner"
}
```

***

## Annotations for specific situations

Add these when the [compile report](https://docs.tensor9.com/byoc/cli/reference.md#compile) asks for one, or when your stack has the situation described.

| Annotation | Goes on | The decision |
| - | - | - |
| `#@link()` | variable | This input may carry a value produced by another of your stacks; the compiler resolves it at install time and passes your own value through unchanged elsewhere. |
| `#@tls_domain(domain_name='example.com', subject_alternative_names=['*.example.com'])` | variable holding a certificate ARN | The domains a certificate passed in from outside the stack covers, so the install can issue an equivalent one. |
| `#@observability_endpoint(type='prometheus')` | variable, data source or local | This value is a telemetry endpoint. The install points it at its own collector. `type` is `'prometheus'`, `'loki'`, `'datadog'` or `'otlp'`. |
| `#@kubernetes_service(type='LoadBalancer')` | `data "kubernetes_service_v1"` | This service is a load balancer, so the install can handle environments that assign it an IP address rather than a hostname. |
| `#@iam(compat='widen')` | IAM policy resource | You accept a grant wider than your original when the target cloud cannot express it exactly. Without it, a wider grant blocks the compile. See [Cross-Cloud IAM](https://docs.tensor9.com/byoc/fundamentals/cross-cloud-iam.md). |
| `#@iam(posture='enforce')` | IAM policy resource | Remove a translated grant your workload provably does not use, rather than keep it and report it. |
| `#@svc_equiv_target(node_type='cache.r6g.large', multi_az='true')` | managed service resource | Your preferred settings where a service's configuration cannot be carried across clouds exactly. |
| `#@artifact_commit()` | attribute inside `locals { }` | The contents of an artifact become a commit on a repository in the install. See [Delivering Artifacts to Git](https://docs.tensor9.com/byoc/fundamentals/artifact-git-delivery.md). |

## Checking your annotations

1. Run `terraform validate` and `terraform plan` against an appropriate environment. Annotations alone leave the plan unchanged. Review any accepted feature settings or source repairs separately.
2. Run [`tensor9 compile`](https://docs.tensor9.com/byoc/cli/reference#compile). The report lists what the compiler set on your behalf (region, namespace, domain) as Informational issues, and anything still needing a decision as Blocking or Recommended.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.