Summary
Establish the same presenter-boundary architecture for cfl that we just completed for jtk.
This issue is the architectural north star for the cfl side of the repo. The goal is not a partial cleanup or a few localized formatter fixes. The goal is a complete migration of cfl default text output onto the same layered model:
domain/API data
-> domain-side projection helpers when needed
-> presenter
-> OutputModel
-> shared pure renderer
-> command writes stdout/stderr
Desired End State
cfl should converge on the same rendering architecture as jtk:
- Commands orchestrate only.
- Presenters own domain-to-presentation mapping.
- The shared renderer owns layout only.
stdout remains the primary result/artifact stream.
stderr remains the diagnostics/advisory/prompt stream.
- JSON/artifact output remains separate and intentionally preserved.
By the end of this migration:
cfl default text output is presenter/renderer based.
- Commands do not build user-facing strings or presenter-owned DTOs.
- Config/env source detection lives outside presenters.
- Shared pure rendering is the main text-rendering path for
cfl.
- Any exceptions are explicit and justified.
Architectural Requirements
1. Commands should orchestrate only
Commands should:
- fetch data
- branch between JSON/artifact and text output
- call presenter
- call shared renderer
- write rendered
stdout / stderr
Commands should not:
- assemble display strings
- construct presenter-owned DTOs
- decide final section ordering for rendered output
- embed formatting rules like suffixes, labels, or pagination wording
2. Presenters should own domain -> presentation mapping
Presenters should decide:
- which fields are shown
- labels and ordering
- whether output is detail/table/message/composite
- empty-state messages
- pagination/advisory messages
- status/mutation wording
- stream destination for commentary vs primary output
3. Renderer should own layout only
The shared pure renderer should remain responsible for:
- agent/human style layout
- table formatting
- detail formatting
- message formatting
- stdout/stderr split according to section metadata
The renderer should not:
- inspect domain types
- normalize domain-specific content ad hoc
- repair string formatting mistakes coming from commands
4. Preserve CLI stream semantics
For cfl, keep the same stream contract:
stdout = primary result/artifact
stderr = warnings, diagnostics, advisory text, progress, confirmation prompts
This matters for both humans and agents.
5. Preserve JSON / artifact contracts
This migration is about default text output.
Do not silently change the JSON/artifact pathway unless there is a separate explicit product decision to do so.
Scope
Migrate all cfl default text output paths to the presenter boundary architecture.
Likely explicit exception:
tools/cfl/internal/cmd/init/init.go
If init is intentionally exempted for the same reason as jtk init, that should be called out explicitly in the implementation plan.
Interactive confirmation prompts may remain direct stderr prompt IO unless we intentionally decide to model them too.
cfl Inventory To Plan Against
Table / list views
These should become presenter-owned table/list sections:
tools/cfl/internal/cmd/space/list.go
tools/cfl/internal/cmd/page/list.go
tools/cfl/internal/cmd/search/search.go
tools/cfl/internal/cmd/attachment/list.go
Special attention:
- pagination / cursor hints are currently written directly to
stderr
- some “no results” paths are still raw text instead of modeled output
Detail / key-value views
These should become presenter-owned detail sections:
tools/cfl/internal/cmd/space/view.go
tools/cfl/internal/cmd/page/view.go
tools/cfl/internal/cmd/configcmd/show.go
Important:
config show currently does source detection and formatting in the command
- that should move to a domain-side config projection helper plus a pure presenter
Mutation / success flows
These should become presenter-owned message/composite outputs:
tools/cfl/internal/cmd/space/create.go
tools/cfl/internal/cmd/space/update.go
tools/cfl/internal/cmd/space/delete.go
tools/cfl/internal/cmd/page/create.go
tools/cfl/internal/cmd/page/edit.go
tools/cfl/internal/cmd/page/copy.go
tools/cfl/internal/cmd/page/delete.go
tools/cfl/internal/cmd/attachment/upload.go
tools/cfl/internal/cmd/attachment/download.go
tools/cfl/internal/cmd/attachment/delete.go
These are mostly Success + key/value composite outputs today and should be modeled as single presenter-owned outcomes.
Diagnostic / composite status flows
These need explicit planning rather than command-local fmt.Fprintln output:
tools/cfl/internal/cmd/configcmd/test.go
tools/cfl/internal/cmd/configcmd/clear.go
- pagination and cursor hints in list/search commands
- warnings such as
tools/cfl/internal/cmd/page/edit.go
Composite / tricky output paths
These should be planned as their own category:
tools/cfl/internal/cmd/page/view.go
tools/cfl/internal/cmd/configcmd/test.go
tools/cfl/internal/cmd/configcmd/clear.go
page view is especially important. It is not just a RenderKeyValue migration. It mixes:
- metadata
- converted content
- raw vs markdown modes
- truncated vs full output
- content-only mode
- web mode
- JSON/artifact output
That path needs a real presenter design, not an ad hoc rewrite.
Required Shared / Root Changes
The implementation plan should include the root-level architecture, not just command-by-command migrations.
cfl currently still routes text output through view.View in tools/cfl/internal/cmd/root/root.go.
The migration should:
- Introduce one authoritative render mode at the
cfl root/options layer.
- Derive both legacy
view behavior and new present renderer style from that same mode during migration.
- End with
cfl primary text output no longer depending on view.Table, v.Success, v.RenderKeyValue, etc.
If the architectural goal is truly “same as jtk,” then cfl should end on the shared pure renderer for text output, not on a permanent mixed path.
What The Implementation Should Add
1. tools/cfl/internal/present
Add a presenter package for cfl, parallel to jtk.
Likely presenters:
SpacePresenter
PagePresenter
AttachmentPresenter
SearchPresenter
ConfigPresenter
2. Domain-side config projection helpers
Config value/source resolution should live outside presenters, likely in tools/cfl/internal/config.
Do not make presenters inspect env vars or load config state.
3. Shared renderer reuse
Reuse the shared pure renderer rather than creating a second cfl-specific rendering engine.
Planning Rules
These should be treated as non-negotiable for the migration:
- No command-local construction of presenter-owned DTOs.
- No command-local user-facing string assembly, except explicit prompt exemptions if we keep them.
- No command-local section ordering for final rendered output.
- No renderer-side normalization of domain content.
- No plan that leaves
cfl half on view.* and half on presenters as the merge target.
Recommended Planning Categories
The implementation plan should group work by output shape, not only by file.
Category A: table/list
space list
page list
search
attachment list
Category B: detail
space view
config show
page view metadata path
Category C: mutation/composite success
- space create/update/delete
- page create/edit/copy/delete
- attachment upload/download/delete
Category D: diagnostic/composite status
config test
config clear
- list/search pagination hints
- warning/advisory paths
Category E: explicit exceptions
Probably:
init
- confirmation prompts
If any exemptions are kept, they should be explicit in the plan.
TDD Expectations
This work should be heavily test-driven, same as jtk.
Expected test structure:
-
Presenter tests first
- Given domain/config values, assert exact
OutputModel.
-
Renderer contract tests
- Assert exact
stdout / stderr output for representative cfl output shapes using the shared renderer.
-
Command wiring tests
- Assert command -> presenter -> render -> write flow.
- Preserve JSON/artifact path tests.
-
Exact assertions for new text contracts
- Prefer exact string assertions over loose substring checks for newly migrated text output.
Verification Expectations
The implementation plan should include explicit verification such as:
# Legacy view text helpers should be gone from cfl commands, except explicit exemptions
rg -n '\\bv\\.(Table|Success|RenderKeyValue|RenderKeyValues|Info|Warning|Error|Println|Render)\\b' tools/cfl/internal/cmd --glob '!**/*_test.go'
# Raw command-local output text should be gone, except prompts/exemptions
rg -n 'fmt\\.F(print|printf|println)\\(opts\\.(Stdout|Stderr),\\s*"' tools/cfl/internal/cmd --glob '!**/*_test.go'
# Once presenters exist, command files should not construct presenter DTOs
# (exact grep depends on final type names/package layout)
Caution
Do not mechanically copy the jtk plan.
cfl has some different shapes and risks:
page view mixes metadata and content rendering
- config source reporting is more explicit and command-local today
- list/search pagination/cursor UX differs from
jtk
- attachment flows still format sizes in command code
The architecture should be reused, but the plan should be specific to cfl.
Success Criteria
This issue is complete when the implementation plan and eventual code leave cfl in the same architectural state as jtk:
- presenter/renderer text pipeline for default output
- commands reduced to orchestration
- presenters own domain-to-presentation mapping
- config/source projection outside presenters
- shared pure renderer as the text path
- explicit handling of any true exceptions
Summary
Establish the same presenter-boundary architecture for
cflthat we just completed forjtk.This issue is the architectural north star for the
cflside of the repo. The goal is not a partial cleanup or a few localized formatter fixes. The goal is a complete migration ofcfldefault text output onto the same layered model:Desired End State
cflshould converge on the same rendering architecture asjtk:stdoutremains the primary result/artifact stream.stderrremains the diagnostics/advisory/prompt stream.By the end of this migration:
cfldefault text output is presenter/renderer based.cfl.Architectural Requirements
1. Commands should orchestrate only
Commands should:
stdout/stderrCommands should not:
2. Presenters should own domain -> presentation mapping
Presenters should decide:
3. Renderer should own layout only
The shared pure renderer should remain responsible for:
The renderer should not:
4. Preserve CLI stream semantics
For
cfl, keep the same stream contract:stdout= primary result/artifactstderr= warnings, diagnostics, advisory text, progress, confirmation promptsThis matters for both humans and agents.
5. Preserve JSON / artifact contracts
This migration is about default text output.
Do not silently change the JSON/artifact pathway unless there is a separate explicit product decision to do so.
Scope
Migrate all
cfldefault text output paths to the presenter boundary architecture.Likely explicit exception:
tools/cfl/internal/cmd/init/init.goIf
initis intentionally exempted for the same reason asjtk init, that should be called out explicitly in the implementation plan.Interactive confirmation prompts may remain direct
stderrprompt IO unless we intentionally decide to model them too.cflInventory To Plan AgainstTable / list views
These should become presenter-owned table/list sections:
tools/cfl/internal/cmd/space/list.gotools/cfl/internal/cmd/page/list.gotools/cfl/internal/cmd/search/search.gotools/cfl/internal/cmd/attachment/list.goSpecial attention:
stderrDetail / key-value views
These should become presenter-owned detail sections:
tools/cfl/internal/cmd/space/view.gotools/cfl/internal/cmd/page/view.gotools/cfl/internal/cmd/configcmd/show.goImportant:
config showcurrently does source detection and formatting in the commandMutation / success flows
These should become presenter-owned message/composite outputs:
tools/cfl/internal/cmd/space/create.gotools/cfl/internal/cmd/space/update.gotools/cfl/internal/cmd/space/delete.gotools/cfl/internal/cmd/page/create.gotools/cfl/internal/cmd/page/edit.gotools/cfl/internal/cmd/page/copy.gotools/cfl/internal/cmd/page/delete.gotools/cfl/internal/cmd/attachment/upload.gotools/cfl/internal/cmd/attachment/download.gotools/cfl/internal/cmd/attachment/delete.goThese are mostly
Success + key/valuecomposite outputs today and should be modeled as single presenter-owned outcomes.Diagnostic / composite status flows
These need explicit planning rather than command-local
fmt.Fprintlnoutput:tools/cfl/internal/cmd/configcmd/test.gotools/cfl/internal/cmd/configcmd/clear.gotools/cfl/internal/cmd/page/edit.goComposite / tricky output paths
These should be planned as their own category:
tools/cfl/internal/cmd/page/view.gotools/cfl/internal/cmd/configcmd/test.gotools/cfl/internal/cmd/configcmd/clear.gopage viewis especially important. It is not just aRenderKeyValuemigration. It mixes:That path needs a real presenter design, not an ad hoc rewrite.
Required Shared / Root Changes
The implementation plan should include the root-level architecture, not just command-by-command migrations.
cflcurrently still routes text output throughview.Viewintools/cfl/internal/cmd/root/root.go.The migration should:
cflroot/options layer.viewbehavior and newpresentrenderer style from that same mode during migration.cflprimary text output no longer depending onview.Table,v.Success,v.RenderKeyValue, etc.If the architectural goal is truly “same as
jtk,” thencflshould end on the shared pure renderer for text output, not on a permanent mixed path.What The Implementation Should Add
1.
tools/cfl/internal/presentAdd a presenter package for
cfl, parallel tojtk.Likely presenters:
SpacePresenterPagePresenterAttachmentPresenterSearchPresenterConfigPresenter2. Domain-side config projection helpers
Config value/source resolution should live outside presenters, likely in
tools/cfl/internal/config.Do not make presenters inspect env vars or load config state.
3. Shared renderer reuse
Reuse the shared pure renderer rather than creating a second
cfl-specific rendering engine.Planning Rules
These should be treated as non-negotiable for the migration:
cflhalf onview.*and half on presenters as the merge target.Recommended Planning Categories
The implementation plan should group work by output shape, not only by file.
Category A: table/list
space listpage listsearchattachment listCategory B: detail
space viewconfig showpage viewmetadata pathCategory C: mutation/composite success
Category D: diagnostic/composite status
config testconfig clearCategory E: explicit exceptions
Probably:
initIf any exemptions are kept, they should be explicit in the plan.
TDD Expectations
This work should be heavily test-driven, same as
jtk.Expected test structure:
Presenter tests first
OutputModel.Renderer contract tests
stdout/stderroutput for representativecfloutput shapes using the shared renderer.Command wiring tests
Exact assertions for new text contracts
Verification Expectations
The implementation plan should include explicit verification such as:
Caution
Do not mechanically copy the
jtkplan.cflhas some different shapes and risks:page viewmixes metadata and content renderingjtkThe architecture should be reused, but the plan should be specific to
cfl.Success Criteria
This issue is complete when the implementation plan and eventual code leave
cflin the same architectural state asjtk: