chant carve (emit / bridge / apply)
Synopsis
Section titled “Synopsis”chant carve emit --from <tf-dir> --select <address> (--state <tfstate> | --env <env> [--live-name <id>]) [-o <dir>]chant carve bridge --from <tf-dir> --select <address> [--apply-rewrites] [-o <dir>]chant carve apply --from <tf-dir> --select <address> --env <env> [--stack <name>] [--write] [--write-source] [-o <dir>]chant carve status [--from <dir>] [--json]Description
Section titled “Description”The carve commands peel a resource out of a Terraform estate into native chant source — incrementally, never the whole estate. The long tail stays in Terraform; “we can’t map this” becomes “leave it where it is,” not a failure. Start with chant carve advise to see what is cheap to carve.
A carve never destroys or recreates. It reuses the adopt-an-orphan loop: Terraform stops managing the resource, chant adopts the still-live resource, and you sit at the observe position until you turn the dial to apply. Every step before graduation is reversible with terraform import.
The flow is three steps.
1. carve emit — adopt into chant source
Section titled “1. carve emit — adopt into chant source”Adopts the selected resource into typed chant source and reports the boundary — every dependency edge the carve would cut. There are two adoption sources:
--state <tfstate>(recommended) adopts offline, straight from the Terraform state file. This is the correct source for a Terraform-managed resource: it is created through the provider API, not CloudFormation, so it is not in any CFN stack, but its resolved attributes are in the state. No cloud call.--env <env>adopts via the live cloud->code import path (for resources already in a CloudFormation stack). It selects by native type; if the stack has several resources of that type, narrow it with--live-name <logical-id>. This path is exercised end to end against a real AWS endpoint byjust carve-emit-e2e(Floci in Docker).
chant carve emit --from ./infra --select aws_s3_bucket.assets --state ./terraform.tfstateThe state path emits a native chant Declarable with CloudFormation-style properties mapped from the Terraform attributes; attributes without a mapping are preserved in a reference comment so nothing is dropped. It covers 78 common AWS carve targets across S3, IAM, DynamoDB, SNS/SQS, Lambda, KMS, Secrets Manager, SSM, ECR, CloudWatch, Route 53, EFS, EC2 (instances + networking), autoscaling, ELBv2, RDS, ElastiCache, API Gateway, Step Functions, ACM, and ECS; advise and emit cover exactly the same AWS types, so there is no rank-it-but-can’t-emit gap. A type outside that set is refused with the supported list, the same way on both --state and --env. Kubernetes types are ranked by advise but cannot be emitted yet. Nothing is patched or applied; the resource lands at the observe position.
After emit, chant lint ./out --lexicon aws audits the adopted resource — advisory findings you may choose to fix, and errors that block chant build (e.g. a bucket with no public-access block). Auditing what you inherited is part of the point.
2. carve bridge — patch the survivors
Section titled “2. carve bridge — patch the survivors”Generates the edits to the Terraform you leave behind so its plan stays valid once the resource is chant-owned.
- Inbound edges (a survivor reads the carved resource) become a
datasource plus rewired references. Required immediately, orterraform planerrors on the dangling reference. - Outbound edges (the carved resource read a survivor) become deferred deploy-time inputs, wired at apply.
chant carve bridge --from ./infra --select aws_s3_bucket.assetsSafe by default: it writes the proposed data sources, rewritten survivor files, and a runbook to an output directory for review. --apply-rewrites edits the survivor .tf in place. The rewrite is idempotent, and it excises the carved resource’s own declaration (and any folded sub-resources) from the survivor source — without that, the next terraform apply would re-create what terraform state rm released.
3. carve apply — graduate
Section titled “3. carve apply — graduate”Resolves the ownership marker that makes the resource chant-owned and finalizes the ordered apply runbook.
chant carve apply --from ./infra --select aws_s3_bucket.assets --env prod --stack assetsThis is BYOL-honest: it makes no cloud call. It computes the marker and the plan; the apply itself is whatever lifecycle you brought — the native CLI, a CI pipeline, an ApplyOp — and it stamps the ownership marker the emitted source carries. --write saves the graduation doc. --write-source stamps the ownership marker into the emitted chant source as well, so the adopted declaration carries the identity chant lifecycle reads back.
4. carve status
Section titled “4. carve status”Read-only. It walks the tree under --from for every *.carve.json manifest the three steps above write. Without --from it walks the current directory. Each carved address prints as one row with the step it has reached, so a renderer no longer has to discover manifests by guessing depth.
chant carve status --from ./infrachant carve status --from ./infra --json--json emits the same rows as one document on stdout. An empty tree says so and points at carve emit.
Manifests record file paths relative to their own directory, so a tree that moves still reads correctly.
The handoff, end to end
Section titled “The handoff, end to end”# 1. see what's cheap to carvechant carve advise --from ./infra
# 2. adopt the bucket into chant source, see its boundarychant carve emit --from ./infra --select aws_s3_bucket.assets --env prod
# 3. Terraform stops managing it (does NOT destroy it)terraform state rm aws_s3_bucket.assets
# 4. patch the survivors so their plan stays validchant carve bridge --from ./infra --select aws_s3_bucket.assets --apply-rewritesterraform plan && terraform apply
# 5. graduate: mark it chant-owned, then apply with your lifecyclechant carve apply --from ./infra --select aws_s3_bucket.assets --env prod --writeAt every step before 5, rollback is terraform import aws_s3_bucket.assets <id>.
These are the emit, boundary-bridging, and apply-graduation phases of the strangler-fig design (#197), built on the read-only advisor (#214). Emit targets a Declarable (a single native resource); a whole service with a deploy pipeline is a Component, not a leaf carve. Removing the carved resource’s own block from the .tf is part of the bridge patch, not a manual runbook step. Emit adopts the AWS types the carve table lists plus kubernetes_manifest, whose kind is read out of the manifest body in state so one rule covers every CRD. The typed kubernetes_* resources and the google types the advisor ranks are refused by emit, and every kubernetes type is refused by bridge until it has a data-source mapping (#2034).