You know that feeling when you have a side project idea, you think "this should be simple", and 3 weeks later you end up with a complete VSCode extension, a CLI, tests, CI/CD, and you wonder how you got there? π
Welcome to the world of vibe coding: this approach where you code through successive iterations, following your creative flow, without planning everything in advance. Today, I'm going to tell you how I transformed a daily frustration with Mistral workflows into a 2000+ line TypeScript VSCode extension.
Spoiler: Claude Code was my copilot, and good prompts made all the difference! π
At my company, we use OpenStack Mistral to orchestrate our automation workflows. If you don't know Mistral, it's a workflow engine that uses YAQL (a query language) and Jinja2 to define tasks, transitions, loops...
A typical Mistral workflow:
version: '2.0'
my_workflow:
input:
- servers
- action
tasks:
validate_input:
action: std.noop
publish:
validated: <% $.servers.len() > 0 %>
on-success:
- deploy_servers: <% $.validated %>
- fail_workflow: <% not $.validated %>
deploy_servers:
When working with OpenStack Mistral, I noticed that errors in YAQL expressions (Yet Another Query Language) were difficult to detect before execution. Developers wasted time debugging syntax errors that could have been detected earlier.
# Classic scenario at 10am
1. You write a 200-line workflow
2. You deploy it to Mistral
3. Error: "Task 'deploy_servers' not found"
β Typo in task name π€
4. You fix it, re-deploy
5. Error: "Unknown variable: deployed_id"
β Missing 's' in deployed_ids π‘
6. You fix it again, re-deploy
7. Error: "Orphaned task: cleanup_on_error"
β Task defined but never called π€¬
8. 45 minutes wasted on errors detectable at write time!The painful stats:
β Classic text editors:
- No YAQL validation
- No task name auto-completion
- No semantic error detection
β yamllint:
- Only validates YAML syntax
- Completely ignores YAQL and Mistral logic
β Existing VSCode extensions:
- None exist for Mistral v2 + YAQL
- Generic YAML extensions are too basicIt was clear: we needed to create our own tool! π οΈ
Vibe coding is an approach where you break down a complex problem into achievable small tasks, using an AI assistant to accelerate development. The key is not to do everything at once, but to progress iteratively.
Initial problem: YAQL errors in Mistral workflows are only detected at runtime.
Goal: Create a VSCode linter that validates YAQL expressions in real-time.
# Example Mistral workflow with YAQL
version: '2.0'
workflow_example:
tasks:
task1:
action: std.echo
input:
output: <% $.data.value %> # YAQL expression to validateBefore coding anything, I explored different approaches:
Option A: Standalone CLI
Advantages:
- Simple to implement
- CI/CD integrable
- Portable
Disadvantages:
- No real-time feedback
- Interrupted workflow (edit β save β lint β fix)
- No auto-completionOption B: VSCode Extension
Advantages:
- Real-time feedback
- Native auto-completion
- Perfect IDE integration
- Optimal UX
Disadvantages:
- More complex to develop
- Requires understanding VSCode API
- Limited to VSCode (but hey, who uses anything else? π)Option C: Language Server Protocol (LSP)
Advantages:
- Compatible with all editors (VSCode, Vim, Emacs...)
- Clean and reusable architecture
- Scalable
Disadvantages:
- VERY complex to implement
- Overkill for a start
- Dev time multiplied by 3I opted for a progressive strategy:
Phase 1: Basic VSCode Extension
β Syntax validation + real-time diagnostics
β Basic auto-completion
β Dev time: ~1 week
Phase 2: Extractable CLI
β Reuse validation core
β CI/CD integration
β Dev time: +2 days
Phase 3: Advanced Features
β Smart snippets
β Signature help for YAQL
β Workflow diagrams
β Dev time: iterative based on needsπ‘ Pro tip: In vibe coding, you don't plan everything. You start with the MVP and iterate based on creative flow!
Instead of asking "Create a complete linter for me", I broke down the project into steps:
<% and %>)Here's the initial prompt I used with Claude Code:
I want to create a VSCode extension to lint Mistral v2 workflows (OpenStack).
Context:
- YAML workflows with YAQL expressions (<% ... %>)
- Need to validate:
1. YAML syntax
2. Mistral semantics (tasks, transitions, variables)
3. YAQL expressions (variables, functions)
Objectives:
- Real-time diagnostics (underlined errors)
- Task name auto-completion
- Clean and extensible TypeScript structure
Questions:
1. What TypeScript architecture do you recommend?
2. How to parse YAML and extract YAQL expressions?
3. How to integrate with VSCode Diagnostic API?Claude Code's Response:
// Proposed Architecture
src/
βββ bin/
β βββ cli.ts // Command-line interface for CI/CD usage
βββ core/
β βββ completionsData.ts // Auto-completion data (YAQL functions, std.* actions)
β βββ diagramGenerator.ts // Generates DOT/Graphviz diagrams of workflows
β βββ helpers.ts // Shared utility functions (parsing, validation)
β βββ types.ts // TypeScript definitions of Mistral structures
β βββ validator.ts // Main validation engine (syntax + semantics)
β βββ yaqlParser.ts // YAQL expression parser (<% ... %>)
βββ extension/
β βββ adapter.ts // Adapter between core and VSCode API
β βββ completions
What I learned: Claude Code excelled at structuring architecture, but you had to break down into specific prompts for each component.
Instead of asking for everything at once, I proceeded with small iterations:
Prompt 1: Parse YAML
Write a YAML parser that:
1. Loads a Mistral workflow file
2. Extracts metadata (version, name, description)
3. Parses tasks and their properties
4. Handles parsing errors properly
Use js-yaml and return a typed TypeScript object.Prompt 2: Extract YAQL
From the parsed YAML, I need to extract all YAQL expressions.
YAQL format: <% expression %>
Contexts to detect:
- In publish: <% $.variable %>
- In on-success/on-error: <% $.condition %>
- In action inputs: <% task().result %>
- In with-items: <% $.list.select($.item) %>
Return a list of {expression, location, context}.Prompt 3: Semantic Validation
Implement the following Mistral validation rules:
1. Valid task names: [a-z0-9_]+ only
2. No duplicate tasks
3. References in requires/on-success/on-error exist
4. YAQL variables are defined:
- workflow inputs
- publish from previous tasks
- task() for results
5. Detect orphaned tasks (never called)
Return a list of diagnostics with severity (error/warning).Once the core was functional, I added features one by one:
Prompt for Auto-completion:
I want to add contextual auto-completion:
Contexts:
1. After "requires:" β suggest available task names
2. After "<% $." β suggest available variables
3. In "action:" β suggest std.* and custom actions
Use VSCode CompletionItemProvider API.
Provide examples with appropriate CompletionItemKind.Prompt for Snippets:
Create VSCode snippets to speed up writing:
1. mistral-workflow: complete workflow skeleton
2. mistral-task: task template with all keys
3. with-items: loop with YAQL
4. retry: retry policy
5. join: join strategy (all/any)
VSCode snippet JSON format with ${1:name} placeholders.Prompt for Diagrams:
I want to generate a DOT (Graphviz) diagram of the workflow.
Elements to represent:
- Nodes: tasks (rectangles)
- Edges: transitions (on-success green, on-error red)
- Clusters: logical groups if tags present
- Entry point: task without requires
Generate DOT code and use VSCode API to display.To make Claude Code even more effective on this project, I created a specific rules file:
.claude/rules.md - Project Rules
# Mistral YAQL Linter - Development Rules
## Architecture
- Separate parsing, validation, and diagnostics
- Each validator is independent and testable
- Use strict TypeScript types everywhere
## Code Conventions
- File names: camelCase.ts
- Classes: PascalCase
- Functions/variables: camelCase
- Constants: SCREAMING_SNAKE_CASE
## Patterns to Follow
1. **Validators**: return `Diagnostic[]`
2. **Parsers**: return typed objects or `null` on error
3. **Providers**: implement VSCode interfaces
## Mistral Business Rules
- Task names: ^[a-z0-9_]+$
- YAQL expressions: between <% and %>
- Available variables: $.inputs, $.publish, task().result
- YAQL functions: len, map, filter, select, where, etc.
## Tests
- One test per validation rule
Here's a prompt template I use systematically:
## Context
I'm working on the Mistral YAQL linter (TypeScript + VSCode).
## Current Problem
[Description of problem or missing feature]
## Objective
[What I want to accomplish]
## Constraints
- Must integrate into existing architecture (src/validators/)
- Must return VSCode-compatible Diagnostic[]
- Must be unit testable
## Use Case Example
[YAML example that should trigger the rule]Here are the prompt templates I use daily. Copy-paste friendly and ready to adapt to your context! π
Feature: [FEATURE NAME]
Context:
- Project: Mistral YAQL Linter (TypeScript VSCode extension)
- Current architecture: [BRIEF DESCRIPTION]
Objective:
[Description in 2-3 sentences of what you want to accomplish]
Technical constraints:
- Must use [TECHNOLOGY/PATTERN]
- Must integrate with [EXISTING COMPONENT]
- Performance: [REQUIREMENT IF RELEVANT]
Usage example:
[Concrete example]
Expected deliverables:
1. Functional TypeScript code
2. Unit tests
3. Inline documentation
Main question:
[Your specific question]Bug Report
Symptom:
[What's not working]
Expected behavior:
[What should happen]
Current behavior:
[What actually happens]
Relevant code:
[Relevant code snippet]
Execution context:
- File: [PATH]
- Function: [NAME]
- Input: [DATA]
Question:
Identify the root cause and propose a fix.Refactoring Request
Current code:
[Your smelly code]
Identified problems:
1. [Code smell #1]
2. [Code smell #2]
Refactoring objective:
- Improve [ASPECT]
- Simplify [PART]
- Make testable [COMPONENT]
Constraints:
- Don't break existing tests
- Keep the same public API
- [Other constraint]
Question:
Propose a refactored version with explanations."Create a complete VSCode extension to validate YAQL
with all possible features"Problem: Too vague, too complex, uncertain result.
1. "Help me parse a YAML file with js-yaml"
2. "How to extract expressions between <% and %>?"
3. "What regex to validate YAQL variables?"
4. "How to create a VSCode diagnostic?"Advantage: Clear progression, testable results, deep understanding.
In the end, vibe coding this Mistral linter is a bit like playing jazz: you have a basic melody (the concept), then you improvise and refine as you go. Claude Code is your saxophonist who follows and enriches your composition.
Key principles of vibe coding:
The project today:
So, ready to vibe code your next side project? Get started, start small, and let the creative flow guide you! π¨
π₯ Bonus challenge: Take a problem that frustrates you daily. Spend 2 hours vibe coding an MVP with Claude Code. Share your result, I bet you'll be surprised at what you can accomplish!
Thanks for following me on this adventure! π
This article was written with β€οΈ for the DevOps community.
PS: The repo is available on GitHub. If you work with Mistral, test the extension and feel free to contribute. And if you vibe code something cool, ping me, I love seeing what others create in flow mode! π