terradart_cli 0.35.0
terradart_cli: ^0.35.0 copied to clipboard
The terradart command — synth, plan, apply and migrate a TerraDart Stack or an existing Terraform tree, and write outputs as a --dart-define-from-file JSON.
Changelog #
0.35.0 - 2026-10-03 #
- Every command's
--helpends withExamples:(the simplest use first, the--no-input --jsonform an agent runs last) andSee also:topics.terradart help <topic>prints a terminal-sized guide —environments,outputs,backends,engines,migrate,exit-codes,json,agents— andterradart help --listlists them;terradart help migrateis the command's usage followed by the guide. --dry-runonapplyanddestroyruns synth,initandplan(plan -destroy) and stops: no question, no state change, no define file. Onoutputsit reads the outputs and prints the define file and its keys without writing it. With--jsonthe result has"dryRun": trueand the command to run without the flag innext.- Breaking: the exit codes are a fixed table, whichever step fails: 1 internal, 2
plan --detailed-exitcodefound changes, 3 an answer is needed, 10 the entry point failed, 11 no engine, 12 the engine failed (it used to pass the engine's own code through), 64 a usage error or missing flag, 65 a wrongterradart:section or unknown--env, 66 nopubspec.yaml.--jsonprints one object on stdout —schemaVersion,command,ok,exitCode,envandenginewith why each is the one,outDir, the plan'sadd/change/destroy/replace(read fromshow -jsonof a saved plan),defineFileandkeys(never the values),notices(skill_outdated,skill_newer),error(code,message,flag,choices,engineExitCode) andnext— and sends the progress, the entry point's and the engine's output to stderr; it implies--no-input.plan --detailed-exitcodeexits 2 when there are changes. SeeMIGRATING.md. - Breaking:
terradartasks only on a terminal — stdin and stdout both one — and never when--no-input,TERRADART_NO_INPUT=1,CI, or an AI agent's shell (AI_AGENT,CURSOR_AGENT,CLAUDECODE,GEMINI_CLI,CODEX_SANDBOX,CODEX_THREAD_ID,OPENCODE) says not to. Without an answer,applyanddestroyneed--auto-approveand otherwise stop beforeinitwith exit code 3;state migrateand the engine-switch guard stop with 3 instead of 64; and the engine gets-input=false. On a terminal, a missing--envis a question listing the environments (env: stg (prompt)), not an error. An error that a flag would fix prints up to three lines — the message,Choices:andNext:, the failed command with the flag added (terradart plan --env dev).--quiet(-q) leaves out the values terradart picked by itself (env:,Using OpenTofu ...). SeeMIGRATING.md. - The package bundles the TerraDart Agent Skill (
skills/terradart/SKILL.md) of its release.terradart skill installwrites it to.agents/skills/terradart/SKILL.mdand.claude/skills/terradart/SKILL.md(--agentspicksagents,claude,cursor,windsurf,copilotorall);terradart skill updaterewrites the installed copies and leaves one with local edits, without a marker or from a newer CLI alone unless--force(exit 5);--dry-runprints the diff.terradart skill statusshows each copy as current, marker-only, outdated, newer, edited, missing or foreign, and--checkexits 4 on anything but current or marker-only. - Each copy records
terradart-versionandterradart-sha256(the content without those two lines) undermetadata:in its front matter, and so does the source, sonpx skills add nozomi-koborinai/terradart#v<version> --skill terradartinstalls the same bytes. terradart init --agent-skillwrites the bundled skill into the new project (--agentspicks where, as forskill install); in a terminal it is the last question. Without it, the project'sAGENTS.mdnamesterradart skill installand thenpx skills addline pinned to the release tag.- When the project's skill is older than the CLI,
synth,plan,apply,destroy,outputsandengineprint one line on stderr namingterradart skill update;TERRADART_NO_SKILL_NOTICE=1turns it off.
0.34.0 - 2026-10-03 #
terradart validate [--env <name>]synthesizes, then runsinit -backend=falseandvalidatein the directory the entry point wrote, with the same engine asplan(managed OpenTofu when neithertofunorterraformis onPATH). It needs no credentials, backend or state, so a CI job can check every environment; arguments after--go tovalidate.- Without
--env,validate,plan,apply,destroyandoutputstake theTERRADART_ENVenvironment variable, else thedefaultEnvofrunEnvironments, else the only environment, and print which one and why (env: dev (TERRADART_ENV),env: dev (default)). An entry point that callsrunStackignoresTERRADART_ENV.applyanddestroyask before running against an environmentTERRADART_ENVordefaultEnvchose, and stop without an answer;--auto-approveskips the question. plan,applyanddestroyno longer run one engine on a state the other wrote without asking. When.terradart/engines.jsonhas no record for the state (right after a migration, or in a fresh clone), they read it — the local state file beforeinit, a remote backend'sstate pullafter it — and tell the engine that wrote it from its provider addresses (registry.terraform.io/registry.opentofu.org) or aterraform_versionolder than OpenTofu. An engineterradartpicked by itself (PATHor the OpenTofu download) then needs a yes on a terminal, and without one stops with exit code 64 and the--engineflag that decides; an engine--engineorpubspec.yamlchose runs with a warning.- A package
terradart migrategenerates carriesterradart: engine: terraform(tofufor a tree run with OpenTofu), so its state stays on the engine it came from. terradart state migrate [--env <name>]moves the state to the backend the Stack configures after its backend changes: it synthesizes, then runs the engine'sinit -migrate-statein the directory the entry point wrote, with the environment'sbackendConfig. It names the full source and target configuration (bucket, prefix, and the rest — not only the backend type) and asks first;--auto-approveskips the question and is required without a terminal. Run it before the nextplanorapply, which reconfigure onto the new backend without copying. When the environment passesbackendConfig, it copies only the state of the environment that last initialized that directory (the recordplanandapplywrite). Another environment, or no record, stops with exit code 64 and tells you to runterradart plan --env <name>first —--auto-approvedoes not skip that. It replaces"$(terradart engine)" -chdir=tf-out init -migrate-state.terradart init [dir]writes a project that plans as it is —pubspec.yaml(terradart_coreand the provider packages at the command's version),lib/env.dart(anEnvenum with each environment's values),lib/stack.dart(provider, backend, one resource, one output),bin/infra.dart(runEnvironments),.gitignore,README.mdandAGENTS.md(the commands and the TerraDart Agent Skill) — intoinfra/by default, then runsdart pub get(--no-pub-get). Flags:--provider google|aws|cloudflare|appwrite,--env <names>,--gcp-project/--aws-region/--aws-account/--cloudflare-account/--appwrite-endpoint/--appwrite-project <env>=<value>,--state-bucket <name>|<env>=<name>(the backend follows the provider: GCS, S3 or Cloudflare R2),--backend local|gcs|s3|r2,--defaults,--[no-]flutter,--dry-run,--force. In a terminal each flag left out is a question — the state one is Do you already have a bucket for Terraform state? — and the run ends with the equivalent command. Without one it never asks and never chooses:--provider,--envand--backend(or--state-bucket) are required, the error names every missing one with a command to edit, and--defaultsacceptsdev,prdand local state. Inside a Flutter app it pointsappExportsat the app'slib/generated/and declaresaddDartDefineOutput(). A directory holding*.tf/*.tf.jsonfiles at any depth (past.terraform/,build/,tf-out/, the Flutter platform folders and the like) is named and pointed atterradart migrate(and offered its report in a terminal) unless--force. Existing files are never overwritten without--force.- Appwrite runs on Terraform: a Stack whose
required_providersnamesappwrite/appwrite(published to the Terraform registry only, which OpenTofu cannot install from) resolves to theterraformonPATH, andvalidate,plan,apply,destroyandoutputsstop beforeinitwith a message naming--engine terraform/terradart.engine: terraformwhen there is none or--engine tofu,engine: tofuor atofuengine_pathasks for OpenTofu.terradart init --provider appwritewritesterradart: engine: terraformintopubspec.yaml.
0.33.0 - 2026-10-02 #
First release, in lockstep with the workspace.
- The
terradartcommand:synthruns the entry point (bin/infra.dart, orterradart.entrypointinpubspec.yaml);plan,applyanddestroysynthesize, then runinitand the engine in the directory it wrote;outputswrites the define file from the applied state without planning or applying;engineprints the binary it runs. - The engine is the first of
--engine-path/--engine(orengine_path/engineinpubspec.yaml), the engine.terradart/engines.jsonrecords for the state,tofuonPATH,terraformonPATH, and OpenTofu 1.13.1 downloaded from its GitHub release — checked against the SHA-256 the package ships, and cached in the user cache directory — on Linux, macOS and Windows, amd64 and arm64. Running a state with another engine than the one that applied it, or an older one, warns first. - Environments come from the entry point:
--env <name>names a member of the enumbin/infra.dartpasses torunEnvironments, and the Terraform directory, workspace and partial backend configuration are the ones it declares. An unknown name lists the known ones. applyandoutputswrite the Stack'saddDartDefineOutput()to.terradart/dart_defines.json(.terradart/dart_defines.<env>.jsonwith--env;--define-output,--define-fileorterradart.dart_definesinpubspec.yamlpick another), gitignore.terradart/, and print theflutter run/flutter buildline that reads it.terradart migrateruns theterradart_migratelibrary (scanModuleTree,migrateTree,migrateModule), including--report,--merge-envsand--lift-workspace. It does not look for apubspec.yaml, sodart pub global activate terradart_climigrates a tree before a Dart project exists.--merge-envswrites anEnvenum and abin/infra.dartthat callsrunEnvironments, andterradart plan --env <name>runs one environment.