Natural Language-Driven Desktop App Development: From Prototype to Distributable Tool

    This article documents a hands-on experiment in building a task management desktop application from scratch on an unfamiliar tech stack using natural language-driven code generation. It covers how reference images can drive UI generation, how data models and multi-view systems (list, kanban, Gantt, calendar, statistics) evolve on a shared state layer, and how to add task dependencies, milestones, flowcharts, and timeline views. It also explains integrating local or cloud LLM capabilities for generating daily work summaries, implementing recurring tasks with structured rules and idempotency, building a token-based theming system, layering the codebase into foundation, utility, domain, view, and integration tiers, and handling data sync and cross-platform distribution. The key takeaway: generation tools shorten the path from idea to working prototype, but data modeling, architectural boundaries, state consistency, observability, and product judgment remain the developer's responsibility.

    Natural Language-Driven Desktop App Development: From Prototype to Distributable Tool

    1. Background: When “Describing Requirements” Starts Replacing “Hand-Writing the Skeleton”

    For the past several years, the developer workflow has been fairly stable: choose a stack, scaffold the project, write the UI, wire up data, add tests. Even with scaffolding tools and component libraries, the upfront repetitive work remains substantial. Recently, a new development approach has been entering the picture—describing intent in natural language and having an intelligent coding tool generate runnable code, with the developer shifting into the role of reviewer, constraint-setter, and integrator.

    This article documents one such experiment: building a task management desktop application from scratch on a desktop tech stack the author was previously unfamiliar with, and gradually pushing the functionality to near-usable quality. The focus is not a review of any specific tool, but a more general technical question:

    When code generation becomes sufficiently capable, what changes in the development path of a small desktop application? Where should developers focus their energy?

    2. Starting Point: Driving UI Generation with a Reference Image

    The initial motivation was simple: validate generation quality on an unfamiliar tech stack. The chosen vehicle was a classic task list application—clear requirements, controllable scope, and room to naturally extend into complexity.

    The first step was not writing code, but providing a UI reference image and letting the tool generate an initial interface from it. The value here is that it skips the “staring at a blank file trying to conceive a layout” stage and directly produces a visualized structure.

    A few lessons from practice:

    • The more specific the reference image, the closer the first output is to expectations. Layout density, color tendencies, and component style all influence the generated result.
    • The first result is often the best. Subsequent attempts to switch styles produced lower quality, usually because the style description was too abstract and lacked an anchorable visual reference.
    • Don’t cram too many demands into a single generation. Describing UI structure and business logic together tends to produce code that “looks complete but is hard to maintain.”

    A reusable approach is: fix the UI skeleton first, then inject functionality in batches. For example:

    1. Step 1: Generate a three-column layout—group list on the left, task list in the middle, detail panel on the right.
    2. Step 2: Add task creation, editing, and completion status toggling to the middle list.
    3. Step 3: Add an expected completion time field to tasks and display it in the list.

    This “small-step commit” approach makes each round of generation verifiable and reversible.

    3. Feature Expansion: From a Single List to a Multi-View System

    Once basic task CRUD was working, features began to expand in natural layers.

    3.1 Layering the Data Model

    Initially there was only a flat task list. As requirements progressed, the model evolved into a multi-level structure:

    • Task: the smallest unit of execution, containing status, priority, and time attributes.
    • TaskGroup: a logical aggregation of tasks for batch management.
    • Project: holds a set of task groups and has its own goals and cycles.
    • ProjectCollection: an organizational layer above projects, used for cross-project views.

    The value of this hierarchy is that it gives subsequent statistics, health calculations, and view switching a unified attachment point. If all fields had been piled onto the task object from the start, later expansion would have been very painful.

    3.2 Building the View System in Parallel

    A single list view quickly became insufficient. Multiple view modes were gradually added:

    View Type Core Purpose Key Implementation Points
    List view Quick browsing and editing Virtual scrolling, inline editing
    Kanban view Task flow by status Drag to change status, in-column ordering
    Gantt view Time spans and dependencies Timeline zoom, dependency lines
    Calendar view Arrangement by date Month/week switching, multi-day tasks
    Statistics view Completion and trends Aggregation, chart rendering

    The difficulty of multiple views is not in any single view itself, but in sharing the same data source. The recommended approach: build all views on top of a unified state management layer; views only handle rendering and interaction dispatch and do not directly hold business data.

    1. State layer (tasks, projects, groups, filter conditions)
    2. ↓ subscribe
    3. View layer (list / kanban / Gantt / calendar / statistics)
    4. ↑ events
    5. Action layer (create, update, drag, batch operations)

    The direct benefit: after dragging a card in the kanban to change its date, the Gantt and calendar views sync automatically—no need to write separate sync logic for each view.

    3.3 “Small Features” Like Drag-and-Drop and Filtering

    Drag-and-drop management, search filtering, and tag filtering are not complex individually, but their combination significantly affects the user experience. Practical recommendations:

    • Drag operations should have clear drop-target feedback and a cancel mechanism.
    • Filter conditions should be composable and savable, not one-off input boxes.
    • All views should share the same filter state, avoiding “the filter is lost when I switch views.”

    4. Advanced Capabilities: Dependencies, Milestones, and Process Expression

    As task counts grow, time-based arrangement alone is insufficient to express real workflows.

    4.1 Task Dependencies and Dependency Lines

    Predecessor/successor relationships can be established between tasks. Implementation notes:

    • Dependencies should form a directed acyclic graph; cycle detection is needed on write.
    • Dependency lines in the Gantt chart need to handle cross-row and cross-screen drawing.
    • After a dependency changes, the time arrangement of related tasks may need recalculation.

    4.2 Milestones

    Milestones are key nodes on the timeline, usually with no duration but requiring highlighting. They can attach to projects or to task groups.

    4.3 Flowchart and Timeline

    On top of dependencies, a flowchart view (emphasizing structure) and a timeline view (emphasizing order) can be derived. Both views have the same data requirements and differ only in rendering strategy, making them suitable for reusing the same dependency data.

    5. Integrating Local Intelligence: Making the Tool “Write Daily Reports”

    An interesting direction: connect local or cloud LLM capabilities into the tool layer so it can generate a daily work summary for the user.

    5.1 Layered Design

    It’s advisable to abstract intelligence capabilities into an independent tool layer rather than scattering them across business code:

    1. Business layer (tasks, projects, views)
    2. ↓ request
    3. Tool layer (prompt assembly, call orchestration, result parsing)
    4. ↓ adapt
    5. Model access layer (local inference service / remote endpoint)

    The benefit: when switching model providers, the business layer needs no changes; it also makes it easy to log calls and control concurrency and retries.

    5.2 Prompts and Result Handling

    The key to generating a daily report is not the model itself but the quality of the context fed to it. Recommended aggregation:

    • Tasks completed today
    • Tasks added today
    • Overdue incomplete tasks
    • Associated projects and priorities

    The output can be structurally parsed and then handed to the UI for rendering, rather than displaying raw text directly. This makes layout and subsequent statistics more controllable.

    5.3 Call Logging and Observability

    Keeping records of intelligent calls is necessary: call time, input summary, output summary, duration, and success status. This helps with troubleshooting and cost evaluation.

    6. Recurring Tasks: Automatically Scheduling Repetitive Work into the Flow

    Recurring tasks solve the problem of “it happens every day, but has to be created manually each time.” Typical rules include:

    • Daily
    • Every three days
    • Weekly
    • Weekly on fixed weekdays
    • Monthly on a fixed date

    Implementation notes:

    1. Rule expression: describe recurrence with structured fields, not natural language strings.
    2. Trigger timing: backfill missed recurring tasks on app startup to avoid gaps when the machine was off.
    3. Completion count: increment the count on each completion to track consistency.
    4. Idempotency: repeated triggers on the same day should not produce duplicate tasks.
    1. Example rule (structured description):
    2. {
    3. "type": "weekly",
    4. "weekdays": [1, 3, 5],
    5. "timeOfDay": "09:00"
    6. }

    7. Theme System: Not Just Changing Colors, but Changing Character

    Many applications’ theme features stop at “swapping the primary color.” This experiment attempted deeper style switching—industrial, retro-futurism, tech-forward, and so on.

    To achieve this, the theme system needs to cover:

    • Color tokens (background, foreground, accent, status colors)
    • Fonts and type scale
    • Corner radius, shadows, border styles
    • Spacing rhythm
    • Icon style

    It’s recommended to organize these as design tokens rather than hardcoding styles in each component:

    1. theme/
    2. tokens/
    3. color.json
    4. typography.json
    5. spacing.json
    6. radius.json
    7. themes/
    8. default.json
    9. industrial.json
    10. retrofuturism.json

    Switching themes then only requires replacing the token set; the component layer needs no changes.

    8. Engineering Layers: Foundation, Utility, and Business

    As features multiply, code quickly gets out of control without layering. The structure that emerged in practice:

    • Foundation layer: app shell, window management, theme system, persistence.
    • Utility layer: icon pool, intelligence integration, common components, formatting utilities.
    • Domain layer: domain models and rules for tasks, projects, groups, dependencies, milestones.
    • View layer: rendering and interaction for each view type.
    • Integration layer: data sync, import/export, distribution packaging.

    The core principle of this layering: dependencies only flow downward. The view layer can depend on the domain layer, but the domain layer should not depend on the view layer in reverse.

    9. Data Sync and Distribution: Toward Genuine Usability

    For a tool to be “genuinely usable,” two more things must be solved:

    9.1 Data Sync

    Options include:

    • File sync based on a version control system
    • A cloud workspace based on a custom API
    • Local-first with a conflict merge strategy

    Whichever path is chosen, conflict resolution rules must be defined upfront; otherwise multi-device use will cause problems.

    9.2 Cross-Platform Distribution

    Desktop applications typically need to cover multiple operating systems. Packaging considerations:

    • Differences in installer formats across platforms
    • Signing and notarization requirements
    • Auto-update mechanisms
    • First-launch initialization flow

    10. Conclusion and Reflections

    Back to the original question: what does natural language-driven development actually change?

    From this experiment, what changed most is the distance from idea to runnable prototype. Efficiency gains in UI generation, feature skeletons, and multi-view construction are obvious. But the following still require the developer’s direct control:

    1. Data model design. Once the model is wrong, all subsequent views and statistics are affected.
    2. Layering and boundaries. Generated code tends to “run but lack structure,” requiring human constraints.
    3. State consistency. When multiple views share data, sync logic cannot rely on generation luck.
    4. Observability and maintainability. Logging, error handling, and call records must be designed proactively.
    5. Product judgment. Which features are worth building and to what degree is still a human decision.

    In other words, tools compress the cost of “writing,” but not the cost of “thinking it through.” For small desktop software, this is both an opportunity and a challenge: the barrier is lower, but being chosen among many similar tools still depends on design quality and engineering reliability.

    For developers, a more realistic strategy may be: treat generation capabilities as an accelerator and concentrate effort on architecture, domain modeling, and experience polish. That way, no matter how tools evolve, the core capabilities remain in your own hands.