Skip to main content
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.
New to annotations? Start with Self-Service Onboarding, or let an agent write them.

Syntax

  • 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


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):

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.
#@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):

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'.

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 for which names need it. Oumi proposal (terraform/variables.tf and terraform/alb.tf):
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. 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):
See Secrets 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.

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). 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.

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.

Annotations for specific situations

Add these when the compile report asks for one, or when your stack has the situation described.

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. 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.