Skip to content

Commit 5c019da

Browse files
dugshubclaude
andcommitted
docs: add ADR-008 and follow-up issues for wizard type system
Documents the architectural decisions and implementation roadmap for the wizard type system (CLI-4, CLI-5, CLI-6). ADR-008 covers: - Framework vs application architecture - Discriminated unions for type-safe extensibility - Tree navigation (MVP) with graph support deferred - Separation of concerns (actions, options, menus) - Unified SessionState across wizard and parser - Global state with optional namespacing - BaseConfig with metadata for introspection - StateValue as JsonValue for flexibility - Specific result types for each protocol Follow-up issues document includes: - Immediate next steps: YAML loader, Python decorators - Core functionality: Action executors, option collectors, navigation - Future enhancements: Plugin registries, graph navigation, discovery - Effort estimates and dependency tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ff67cf9 commit 5c019da

File tree

3 files changed

+1555
-0
lines changed

3 files changed

+1555
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# ADR-008: Wizard Type System Architecture
2+
3+
## Status
4+
Accepted
5+
6+
## Context
7+
CLI-4 requires defining the core type system for wizard configuration. We needed to decide how to structure types, handle extensibility, integrate with the parser system, and manage state across the framework.
8+
9+
## Decision
10+
We will implement a **comprehensive wizard type system** with the following design choices:
11+
12+
### 1. Framework Architecture
13+
CLI Patterns is a **framework, not an application**. Users install it and create their own wizard configurations via YAML or Python.
14+
15+
### 2. Discriminated Unions for Extensibility
16+
Use discriminated unions NOW for type-safe extensibility:
17+
```python
18+
class BashActionConfig(BaseConfig):
19+
type: Literal["bash"] = "bash"
20+
command: str
21+
22+
class PythonActionConfig(BaseConfig):
23+
type: Literal["python"] = "python"
24+
module: str
25+
function: str
26+
27+
ActionConfigUnion = Union[BashActionConfig, PythonActionConfig]
28+
```
29+
30+
Add registry system LATER when users need custom types beyond what we provide.
31+
32+
### 3. Tree Navigation (MVP)
33+
- Menus point to target branches (tree structure)
34+
- Navigation history tracked for "back" functionality
35+
- Graph navigation (any→any, cycles, conditions) deferred to future tickets
36+
- Easily extensible: add optional fields to MenuConfig later
37+
38+
### 4. Separation of Concerns
39+
Keep actions, options, and menus separate:
40+
- **Actions**: Execute something (bash, python, etc.)
41+
- **Options**: Configure state (paths, selections, settings)
42+
- **Menus**: Navigate between branches
43+
44+
Do NOT conflate (e.g., no actions in menus). Sequences/chaining added later if needed.
45+
46+
### 5. Built-in System Commands
47+
Framework provides system commands automatically:
48+
- `back` - Navigate to previous branch via history
49+
- `quit`/`exit` - Exit wizard
50+
- `help` - Context-sensitive help
51+
52+
These are NOT defined in YAML/Python configs; they're always available.
53+
54+
### 6. Unified SessionState
55+
Single state model shared between wizard and parser:
56+
```python
57+
class SessionState(StrictModel):
58+
# Wizard state
59+
current_branch: BranchId
60+
navigation_history: list[BranchId]
61+
option_values: dict[OptionKey, StateValue]
62+
63+
# Parser state
64+
parse_mode: ParseMode
65+
command_history: list[str]
66+
67+
# Shared
68+
variables: dict[str, Any]
69+
```
70+
71+
Replaces parser's separate `Context` type. Both systems read/write to SessionState.
72+
73+
### 7. Global State with Namespacing
74+
- All option values stored globally in `option_values` dict
75+
- Options flow between branches by default
76+
- Users can namespace options if isolation needed: `"main.dev_schema"` vs `"models.dev_schema"`
77+
- Per-branch state scoping deferred to future if needed
78+
79+
### 8. BaseConfig with Metadata
80+
All config types inherit from BaseConfig:
81+
```python
82+
class BaseConfig(StrictModel):
83+
metadata: dict[str, Any] = Field(default_factory=dict)
84+
tags: list[str] = Field(default_factory=list)
85+
```
86+
87+
Enables introspection, filtering, documentation generation, and custom tooling.
88+
89+
### 9. StateValue as JsonValue
90+
Use `JsonValue` type (anything JSON-serializable) instead of limited union:
91+
- Supports primitives: str, int, float, bool, None
92+
- Supports collections: lists, dicts
93+
- Supports nesting
94+
- Aligns with YAML/JSON definition loading
95+
96+
### 10. Specific Result Types
97+
Each protocol operation returns a specific result type:
98+
- `ActionResult` - for action execution
99+
- `CollectionResult` - for option collection
100+
- `NavigationResult` - for navigation
101+
102+
Provides structured success/failure with error messages.
103+
104+
## Consequences
105+
106+
### Positive
107+
- **Type safety**: Full MyPy strict mode compliance with discriminated unions
108+
- **Extensibility**: Easy to add new action/option types without breaking changes
109+
- **Integration**: Parser and wizard share state seamlessly
110+
- **Clarity**: Clear separation between actions, options, menus
111+
- **Evolution path**: Tree→graph, static→dynamic, simple→complex
112+
- **Framework flexibility**: Users configure their own wizards
113+
- **Introspection**: Metadata enables tooling and documentation
114+
115+
### Negative
116+
- **Initial complexity**: More upfront type definitions than minimal approach
117+
- **Migration**: Parser Context must be migrated to SessionState
118+
- **Learning curve**: Discriminated unions require understanding
119+
- **Global state**: Potential for unexpected sharing between branches
120+
121+
### Neutral
122+
- Tree navigation sufficient for MVP, graph deferred
123+
- Registry system deferred until users need custom types
124+
- Per-branch state scoping deferred unless requested
125+
126+
## Implementation Plan
127+
128+
### Phase 1: Core Types (`core/types.py`)
129+
- Semantic types: `BranchId`, `ActionId`, `OptionKey`, `MenuId`
130+
- Factory functions with optional validation
131+
- Type guards for runtime checking
132+
- `StateValue = JsonValue`
133+
134+
### Phase 2: Models (`core/models.py`)
135+
- `BaseConfig` with metadata/tags
136+
- Discriminated unions: `ActionConfigUnion`, `OptionConfigUnion`
137+
- `BranchConfig`, `MenuConfig`, `WizardConfig`
138+
- `SessionState` (unified wizard + parser)
139+
- Result types: `ActionResult`, `CollectionResult`, `NavigationResult`
140+
141+
### Phase 3: Protocols (`core/protocols.py`)
142+
- `ActionExecutor`, `OptionCollector`, `NavigationController`
143+
- All use `SessionState` and return specific result types
144+
145+
### Phase 4: Tests
146+
- Semantic type validation
147+
- Model validation (Pydantic rules)
148+
- Discriminated union discrimination
149+
- SessionState integration
150+
151+
## Future Work
152+
153+
### Near-term (Next Sprint)
154+
- Migrate parser Context to SessionState (CLI-XX)
155+
- YAML loader implementation (CLI-XX)
156+
- Python decorator system (CLI-XX)
157+
158+
### Mid-term (Later Sprints)
159+
- Action type registry (CLI-XX)
160+
- Option type registry (CLI-XX)
161+
- Graph navigation support (CLI-XX)
162+
- Project discovery system (CLI-XX)
163+
164+
### Long-term (Future)
165+
- Per-branch state scoping (if needed)
166+
- Action sequences/chaining (if needed)
167+
- Conditional navigation (if needed)
168+
- Remote execution support (if needed)
169+
170+
## References
171+
- [ADR-005: Type System Design](./ADR-005-type-system.md)
172+
- [ADR-002: Hybrid Definition System](./ADR-002-hybrid-definitions.md)
173+
- [ADR-004: Branch-Level UI Protocol](./ADR-004-branch-ui-protocol.md)
174+
- [ADR-007: Composable Parser System](./ADR-007-composable-parser-system.md)
175+
- CLI-4 Refinement Session (2025-09-30)
176+
177+
## Example: DBT Wizard
178+
179+
```yaml
180+
name: dbt-wizard
181+
version: 1.0.0
182+
entry_branch: main
183+
184+
branches:
185+
- id: main
186+
title: "DBT Project Manager"
187+
188+
options:
189+
- id: dbt_project
190+
type: path
191+
name: "DBT Project Path"
192+
default: "./dbt_project.yml"
193+
194+
- id: dev_schema
195+
type: string
196+
name: "Dev Schema"
197+
default: "dbt_dev"
198+
199+
actions:
200+
- id: dbt_run
201+
type: bash
202+
name: "Run DBT"
203+
command: "dbt run --project-dir ${option:dbt_project}"
204+
205+
- id: dbt_build
206+
type: bash
207+
name: "Build DBT"
208+
command: "dbt build --project-dir ${option:dbt_project}"
209+
210+
menus:
211+
- id: menu_projects
212+
label: "Manage Projects"
213+
target: dbt_projects
214+
215+
- id: menu_models
216+
label: "Browse Models"
217+
target: dbt_models
218+
219+
- id: dbt_projects
220+
title: "DBT Projects"
221+
# back, quit, help automatically available
222+
actions:
223+
- id: list_projects
224+
type: bash
225+
name: "List Projects"
226+
command: "find . -name dbt_project.yml"
227+
```
228+
229+
This demonstrates:
230+
- Tree navigation (main → projects, main → models)
231+
- Options flow globally (dbt_project usable in any branch)
232+
- Actions use variable interpolation (${option:dbt_project})
233+
- Built-in commands (back) not defined in YAML

0 commit comments

Comments
 (0)