You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Design and tracking, in the shape of #230 and #234: what behold would show for a choudoufu estate, what it would read to show it, how choudoufu's carve relates to the chant carve lens behold already draws, and where the line stays. Nothing here starts a build; it records the assessment so the premise an earlier comparison note carried ("behold support is premised, not real") has a home now that the choudoufu half of it shipped.
What choudoufu is, for a renderer
An OpenTofu fork, AWS only, where ownership lives on the resource as two tags, tofu-estate and tofu-address (continuation tags for long addresses, tofu-slot for count). live/MARKERS.md is the one integration surface external tools may rely on. The state file is a cache that is allowed to be stale; values with no cloud home go to a record store, effects go to receipts. A cross-estate reference is an ordinary data source filtered on the producer's marker tags (live/OUTPUTS.md). Ownership moves by rewriting the estate tag: live-mv -from-estate.
Since v0.12.0 (2026-09-04) the four reads a renderer needs exist, filed from this assessment and shipped the same day:
every resource under the estate tag, ARN, type, decoded address, raw markers; with DIR, the declared instances the listing cannot see, named by rung (record, declaration-carried)
the declared half
live-check -json (choudoufu#790)
instances[] with type and rung; references[], the marker-filtered data sources, as {from, estate, address} plus the readers; no cloud call
drift
live-plan -estate <e> -json (choudoufu#788)
bound[] with binding source, omissions[] with reasons, unowned[] with the adopting tag write
a move
live-mv -json [-dry-run] (choudoufu#791)
resource, from/to, followers, a stable refusal code; request_id is in the shape but empty today
The joins, mapped to what exists
The palette needs no new word.bound is good, unowned is warn, an instance in omissions because nothing carries its marker is accent, and a record or declaration-carried gap is neutral: behold's existing "did not look", which is the right claim for an instance whose identity has no tag to find. This is reclassifyOverlay's vocabulary (src/overlay.ts) fed from a different source.
Estates are members. Each tofu-estate value is one box in the estate compose (src/estate.ts, graph: multi-project / multi-estate view (Argo app-of-apps) #31). live-check's references[] are the cross-member edges, stated by the tool rather than inferred; behold's value-match pass (src/value-match.ts) has the same shape and would not be needed here.
The live read is one call under read-only IAM.live-ls replaces the resourcegroupstaggingapi get-resources plus per-role list-role-tags the workbench hand-rolled, with the tagging index's roughly one-minute lag handled by -consistent. behold shells the project's choudoufu the way it shells the project's chant, and holds no credentials of its own beyond the ambient read role.
The declared half comes from the tool, not from HCL. behold parses no HCL (the carve lens made the advise report the contract for the same reason). live-check -json is the equivalent contract for a choudoufu estate: the roster is the node set, references[] the edge set, the rung a node attribute the inspect pane states.
A move plan is a morph. The workbench's carve.json ({from, estates[], moves[{address, from, to}]}) is a set of cards changing boxes. renderCarveMorph (src/render.ts) already draws a card gliding from one box to another; a choudoufu move plan is the same picture with the ghosted destination the workbench's Preview phase draws. live-mv -json -dry-run is the per-move confirmation, and the real run's document is the receipt.
The two carves
chant's carve changes representation and owning tool: HCL becomes typed chant source, and ownership moves from a state file to chant's marker, through advise, emit, bridge and apply. choudoufu's carve changes owner only: the resource stays HCL, its block moves between directories, and one tag write moves the boundary; untaggable children follow the parent's live tag.
Structurally they are one operation on one graph: choose a cut, move nodes across it, patch every edge that crosses the cut into a data-source read. chant's advisor prices exactly that (12 points per inbound edge, each one a data-source patch). choudoufu's planner (tlmig/carve.py) fills rows by module, prefix, type or name and has no cost input; live-check's references[] now gives it one, and the advisor's arithmetic applies to it unchanged. "Leave in Terraform" reads as "leave in this estate".
The convergence worth recording: chant's AWS lexicon also puts an ownership marker on the resource as a tag. Both systems agree ownership lives on the resource. So a choudoufu resource graduating to chant is, in principle, one marker rewrite rather than the terraform state rm ceremony the carve Handoff step hands back today. That is a chant question (does carve apply accept a choudoufu-marked resource as its input), not a behold one, and it is noted here so it is not lost.
The line
behold never writes to a cloud. live-mv is a tags-only apply through the provider with its own five refusals, which makes it safer than state surgery, and it is still a cloud write. It stays a handoff: render the move plan, hand back the live-mv lines with copy buttons, read the -json document afterwards. No /api/choudoufu/mv, for the same reason there is no /api/carve/apply (AGENTS.md, "Invariant"). If the demo path ever boots a floci for this, it goes through assertScratch (src/scratch.ts) with its own name and port; the workbench's compose already publishes floci on 127.0.0.1:4650, not :4566.
The fixture
examples/live-mv-workbench in the choudoufu checkout. just up stands floci and the demo up in two containers; a run leaves runs/<id>/ with manifest.json, events.jsonl (inventory, preview, measure, verdict events), carve.json, and one working directory per estate. The demo seed applies the terralith with choudoufu directly (the live block is in the fixture HCL), so the stock-to-choudoufu migration is the adopt form (seed --config --estate --state --approve, via live-import) and not the button path. A first behold lens could read a run directory with no choudoufu call at all; the real member reads the four verbs above.
Proposed order, when something pulls it
A choudoufu estate member kind: live-check -json for the roster and edges, live-ls -json for the live half, the palette join above. Comparable in size to src/helm-releases.ts or src/carve-lens.ts, with tests off recorded -json documents.
live-plan -json as the per-node drift detail in the inspect pane, where /api/diff slices chant's today.
The move-plan morph over carve.json, with the handoff as above.
A demo entry pointing at the workbench, gated on docker and a choudoufu on PATH, if the walkthrough earns it.
What this deliberately does not decide
Whether behold shells choudoufu or reads its documents from disk; whether a choudoufu member can sit in the same estate as chant members (the tags say yes, the edge join says nothing yet); what a choudoufu estate's .behold.json would declare. Each is a build-time question against a shipped contract, and none needs a chant change.
Refs: choudoufu#788 #789 #790 #791 (all shipped v0.12.0); behold #230 (the chant carve lens this rhymes with), #234 (the operating loop's join discipline this follows).
Design and tracking, in the shape of #230 and #234: what behold would show for a choudoufu estate, what it would read to show it, how choudoufu's carve relates to the chant carve lens behold already draws, and where the line stays. Nothing here starts a build; it records the assessment so the premise an earlier comparison note carried ("behold support is premised, not real") has a home now that the choudoufu half of it shipped.
What choudoufu is, for a renderer
An OpenTofu fork, AWS only, where ownership lives on the resource as two tags,
tofu-estateandtofu-address(continuation tags for long addresses,tofu-slotforcount).live/MARKERS.mdis the one integration surface external tools may rely on. The state file is a cache that is allowed to be stale; values with no cloud home go to a record store, effects go to receipts. A cross-estate reference is an ordinary data source filtered on the producer's marker tags (live/OUTPUTS.md). Ownership moves by rewriting the estate tag:live-mv -from-estate.Since v0.12.0 (2026-09-04) the four reads a renderer needs exist, filed from this assessment and shipped the same day:
live-ls -estate <e> -json [-consistent] [DIR](choudoufu#789)record,declaration-carried)live-check -json(choudoufu#790)instances[]with type and rung;references[], the marker-filtered data sources, as{from, estate, address}plus the readers; no cloud calllive-plan -estate <e> -json(choudoufu#788)bound[]with binding source,omissions[]with reasons,unowned[]with the adopting tag writelive-mv -json [-dry-run](choudoufu#791)from/to, followers, a stable refusal code;request_idis in the shape but empty todayThe joins, mapped to what exists
The palette needs no new word.
boundisgood,unownediswarn, an instance inomissionsbecause nothing carries its marker isaccent, and arecordordeclaration-carriedgap isneutral: behold's existing "did not look", which is the right claim for an instance whose identity has no tag to find. This isreclassifyOverlay's vocabulary (src/overlay.ts) fed from a different source.Estates are members. Each
tofu-estatevalue is one box in the estate compose (src/estate.ts, graph: multi-project / multi-estate view (Argo app-of-apps) #31).live-check'sreferences[]are the cross-member edges, stated by the tool rather than inferred; behold's value-match pass (src/value-match.ts) has the same shape and would not be needed here.The live read is one call under read-only IAM.
live-lsreplaces theresourcegroupstaggingapi get-resourcesplus per-rolelist-role-tagsthe workbench hand-rolled, with the tagging index's roughly one-minute lag handled by-consistent. behold shells the project's choudoufu the way it shells the project's chant, and holds no credentials of its own beyond the ambient read role.The declared half comes from the tool, not from HCL. behold parses no HCL (the carve lens made the advise report the contract for the same reason).
live-check -jsonis the equivalent contract for a choudoufu estate: the roster is the node set,references[]the edge set, the rung a node attribute the inspect pane states.A move plan is a morph. The workbench's
carve.json({from, estates[], moves[{address, from, to}]}) is a set of cards changing boxes.renderCarveMorph(src/render.ts) already draws a card gliding from one box to another; a choudoufu move plan is the same picture with the ghosted destination the workbench's Preview phase draws.live-mv -json -dry-runis the per-move confirmation, and the real run's document is the receipt.The two carves
chant's carve changes representation and owning tool: HCL becomes typed chant source, and ownership moves from a state file to chant's marker, through advise, emit, bridge and apply. choudoufu's carve changes owner only: the resource stays HCL, its block moves between directories, and one tag write moves the boundary; untaggable children follow the parent's live tag.
Structurally they are one operation on one graph: choose a cut, move nodes across it, patch every edge that crosses the cut into a data-source read. chant's advisor prices exactly that (12 points per inbound edge, each one a data-source patch). choudoufu's planner (
tlmig/carve.py) fills rows by module, prefix, type or name and has no cost input;live-check'sreferences[]now gives it one, and the advisor's arithmetic applies to it unchanged. "Leave in Terraform" reads as "leave in this estate".The convergence worth recording: chant's AWS lexicon also puts an ownership marker on the resource as a tag. Both systems agree ownership lives on the resource. So a choudoufu resource graduating to chant is, in principle, one marker rewrite rather than the
terraform state rmceremony the carve Handoff step hands back today. That is a chant question (doescarve applyaccept a choudoufu-marked resource as its input), not a behold one, and it is noted here so it is not lost.The line
behold never writes to a cloud.
live-mvis a tags-only apply through the provider with its own five refusals, which makes it safer than state surgery, and it is still a cloud write. It stays a handoff: render the move plan, hand back thelive-mvlines with copy buttons, read the-jsondocument afterwards. No/api/choudoufu/mv, for the same reason there is no/api/carve/apply(AGENTS.md, "Invariant"). If the demo path ever boots a floci for this, it goes throughassertScratch(src/scratch.ts) with its own name and port; the workbench's compose already publishes floci on 127.0.0.1:4650, not :4566.The fixture
examples/live-mv-workbenchin the choudoufu checkout.just upstands floci and the demo up in two containers; a run leavesruns/<id>/withmanifest.json,events.jsonl(inventory, preview, measure, verdict events),carve.json, and one working directory per estate. The demo seed applies the terralith with choudoufu directly (theliveblock is in the fixture HCL), so the stock-to-choudoufu migration is the adopt form (seed --config --estate --state --approve, vialive-import) and not the button path. A first behold lens could read a run directory with no choudoufu call at all; the real member reads the four verbs above.Proposed order, when something pulls it
choudoufuestate member kind:live-check -jsonfor the roster and edges,live-ls -jsonfor the live half, the palette join above. Comparable in size to src/helm-releases.ts or src/carve-lens.ts, with tests off recorded-jsondocuments.live-plan -jsonas the per-node drift detail in the inspect pane, where/api/diffslices chant's today.carve.json, with the handoff as above.What this deliberately does not decide
Whether behold shells choudoufu or reads its documents from disk; whether a choudoufu member can sit in the same estate as chant members (the tags say yes, the edge join says nothing yet); what a choudoufu estate's
.behold.jsonwould declare. Each is a build-time question against a shipped contract, and none needs a chant change.Refs: choudoufu#788 #789 #790 #791 (all shipped v0.12.0); behold #230 (the chant carve lens this rhymes with), #234 (the operating loop's join discipline this follows).
🤖 Claude Code — https://claude.ai/code/session_01RWASk8sLh3pJAQX7TkYGuT