Skip to content

Look at a choudoufu estate

llms.txtlists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
Show the whole prompt
Read https://intentius.io/behold/using/choudoufu/.
Start `npx @intentius/behold demo choudoufu-estate`, or serve this estate with `npx @intentius/behold serve . --env <env>`.
Tell me the URL and list the cards that read unowned.
Copy out each move preview for me to run.
Never deploy with the Deploy button, `POST /api/apply` or `POST /api/ci/dispatch`. Gate approvals stay mine as well (`/api/ops/:name/signal/:gate`, `/api/workspace/gates/approve`, `/api/operator/approve/:op/:gate`). Op runs (`/api/ops/:name/run`) and rollbacks (`/api/rollback`) are mine too. Leave `--auto-sync` off, and keep a `behold preview` or `--public` serve read-only.

choudoufu is an OpenTofu fork whose ownership lives in two AWS tags rather than in a state file. behold draws such an estate as a member kind of its own, beside chant projects and Terraform roots.

Terminal window
npx @intentius/behold demo choudoufu-estate # four estates on a scratch emulator
npx @intentius/behold serve ./my-estate --env live

This is the one thing worth getting right before reading anything else.

The overlay is composed from live-ls -json and live-plan -json, and those two documents answer one question: is this resource bound, unowned, omitted, or invisible to the listing. Neither of them ever compares an attribute value.

So a resource whose tag or path was changed out of band still carries its markers, is still bound, and is still green. Read a green card as this is ours, never as nothing changed.

colour choudoufu’s word means
green bound a declared instance matched a live object
amber unowned a live object at a declared identity that is not ours
blue pending the plan would create it
grey not observed the listing could not see it, or neither document mentions it

Those are choudoufu’s words, not chant’s, and the legend says so. A bound resource is not “managed”: a resource bound by derived identity carries no marker yet, and claiming it is managed would claim a marker that is not there.

Since the ownership read never compares a value, “would a plan change anything?” is a second read you ask for: ⌘K → Re-check live with plan.

It costs differently. The ownership read is answered out of the tagging index and is flat in the estate’s size; a plan refreshes every resource, one provider read per card, which is 301 of them on the estate behold is sized against. So it never runs on an ordinary overlay.

A bound card that drifted stays bound and stays counted as bound. It gains a dashed edge and a ~ n attributes corner, because the ownership verdict is still the card’s colour.

Two different situations, and the difference is where the identity comes from.

Unowned is a live object sitting at an identity the configuration declares. The claim needs no evidence, because the identity is the match. The card leads with the two marker tags that adopt it.

Adoptable is a live object the estate-wide sweep found for a declaration that names no identity at all: a VPC, say, whose vpc-… id EC2 assigns at create time and which nothing in the configuration reconstructs. choudoufu matches it by content instead, comparing the identity-bearing arguments for that resource type.

An adoptable card leads with choudoufu’s own adopt command, and carries matchedOn: the arguments the sweep compared. behold composes no command of its own, and shows the evidence because a person about to stamp two tags onto somebody’s resource is owed it.

Content matching covers a closed list of resource types. A type outside it can never produce an adoptable row, which is a property of the type rather than of your estate.

The sweep is bounded by the account rather than by the estate, and behold polls, so it cannot be on by default. Turn it on for a serve:

{ "spawnEnv": { "TOFU_LIVE_COLLECT_UNCLAIMED": "1" } }

Without it, adoptable is empty on every run. Which is why an empty result says which empty it is:

  • the sweep listed every aws_vpc and matched none of them to this declaration, so the question was asked and answered.
  • this run did not sweep the account, so nothing was looked for, and the line names the variable that asks it.

Reporting the second as the first would be an absence of evidence dressed as evidence of absence.

Each bound card wears a small tag on its top-right edge. The tag is filled when the resource wears this estate’s marker as live-ls lists it. An inline policy has no tags argument and so no marker of its own, and its tag is outlined. The tag’s tooltip and the inspect pane say how the plan found the resource: marker when the estate-wide tag sweep bound it, derived when the configuration names it. choudoufu binds a named resource, such as an IAM role or a log group, by its name whether or not a marker is on it, so a stamped log group reads derived with a filled tag.

npx behold demo terralith takes one stock Terraform root to four estates on a scratch floci. It starts with 23 resources in one state file on S3. The adopt phase runs terragucci’s backends migration. There choudoufu live-import stamps the marker on each resource it verifies and leaves the state file as it was. Split runs the moves migration, which adds three team roots while choudoufu live-mv moves each team’s resources into the team’s estate. split.json keeps the record, and the team boxes appear as the cards glide into them. The plan phase changes all four estates in one step and plans it without applying anything. The terralith outputs a shared setting, and each team root plans against that planned value with -estate-outputs-from. The page outlines each team’s cone, badges a root that planned in full with choudoufu’s reason, draws an edge for the planned output to each root that reads it, and brackets the team boxes whose identical changes live-summary folds into one group.

You run each phase’s line in the demo copy, and the page at /terralith reads the documents it leaves in snapshots/.

GET /api/choudoufu/split reads a split.json plan (or the live-mv workbench’s carve.json, which reads the same) from inside a served member and previews each move with live-mv -json -dry-run, handing the lines back with copy buttons. /choudoufu/split draws the plan as a morph: every member a box, a new box for each estate the plan names that is not served yet, and the moved cards gliding into place. The names from before, /api/choudoufu/moves and /choudoufu/morph, keep working.

There is no /api/choudoufu/mv, and a test asserts it stays absent. A move is one tag write against somebody’s account. behold previews it and reads the receipt afterwards; the write is yours to run, which is the line the carve walkthrough draws around terraform state rm.

behold