-
Notifications
You must be signed in to change notification settings - Fork 417
bug: Skills not loading in Vibe 2.7.0 (0 skills detected despite correct config and valid skill files) #545
Description
Component
CLI
Summary
Despite correct configuration and valid skill files, Mistral Vibe 2.7.0 reports "0 skills" and fails to load any custom skills. No errors or warnings are logged, making debugging difficult.
Steps to Reproduce:
Reproduction steps
- Install Mistral Vibe 2.7.0 on Ubuntu (Python 3.12.3).
- Create a skill directory and file:
mkdir -p ~/.vibe/skills/test-skill
~/.vibe/skills/test-skill/skill.md:
name: test-skill
description: A test skill
license: MIT
user-invocable: true
triggers:
- test
Instructions
This is a test skill.
- Update ~/.vibe/config.toml:
enabled_skills = ["test-skill"]
skill_paths = ["~/.vibe/skills"]
auto_load_skills = true
- Restart Vibe. Type / or /test—no skills appear.
- Run vibe 2>&1 | tee vibe.log and check for skill-related output:
3 models · 0 MCP servers · 0 skills
No errors or warnings are logged.
Expected Behavior:
The skill should appear in the / autocompletion menu.
Typing /test should invoke the skill.
Logs should indicate if skills fail to load (e.g., due to invalid YAML or missing fields).
Actual Behavior:
Vibe reports "0 skills" and ignores all custom skills.
No feedback or error messages are provided.
~/.vibe/logs/ is empty.
Environment:
Vibe version: 2.7.0
OS: Ubuntu
Python: 3.12.3
Config and skill files attached (or paste the contents above).
Additional Notes:
Tested with both minimal and complex skill files.
Permissions are correct (755 for directories, 644 for files).
This blocks users from extending Vibe with custom workflows.
Possible Causes:
Silent failure in skill discovery/loading logic.
Missing debug logs for skill system.
Regression in 2.7.0.
Versions / environment
2.7.0
Logs & screenshots
meta.json
{
"session_id": "621d925a-aec2-4cfe-89d7-0eb286c7fa16",
"start_time": "2026-03-29T10:05:47.411270+00:00",
"end_time": "2026-03-29T10:05:57.193788+00:00",
"git_commit": "dc4080bcad09df70b283c0de07f20e020fd2a6ff",
"git_branch": "main",
"environment": {
"working_directory": "/home/david-carvalho/projects/vestra"
},
"username": "david-carvalho",
"stats": {
"steps": 2,
"session_prompt_tokens": 8313,
"session_completion_tokens": 14,
"tool_calls_agreed": 0,
"tool_calls_rejected": 1,
"tool_calls_failed": 0,
"tool_calls_succeeded": 0,
"context_tokens": 8327,
"last_turn_prompt_tokens": 8313,
"last_turn_completion_tokens": 14,
"last_turn_duration": 1.0600185959992814,
"tokens_per_second": 13.20731546865192,
"input_price_per_million": 0.4,
"output_price_per_million": 2.0,
"session_total_llm_tokens": 8327,
"last_turn_total_tokens": 8327,
"session_cost": 0.0033531999999999998
},
"title": "/test",
"total_messages": 3,
"tools_available": [
{
"type": "function",
"function": {
"name": "web_fetch",
"description": "Fetch content from a URL. Converts HTML to markdown for readability.",
"parameters": {
"properties": {
"url": {
"description": "URL to fetch (http/https)",
"type": "string"
},
"timeout": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Timeout in seconds (max 120)"
}
},
"required": [
"url"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read a UTF-8 file, returning content from a specific line range. Reading is capped by a byte limit for safety.",
"parameters": {
"properties": {
"path": {
"type": "string"
},
"offset": {
"default": 0,
"description": "Line number to start reading from (0-indexed, inclusive).",
"type": "integer"
},
"limit": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Maximum number of lines to read."
}
},
"required": [
"path"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "search_replace",
"description": "Replace sections of files using SEARCH/REPLACE blocks. Supports fuzzy matching and detailed error reporting. Format: <<<<<<< SEARCH\\n[text]\\n=======\\n[replacement]\\n>>>>>>> REPLACE",
"parameters": {
"properties": {
"file_path": {
"type": "string"
},
"content": {
"type": "string"
}
},
"required": [
"file_path",
"content"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "todo",
"description": "Manage todos. Use action='read' to view, action='write' with complete list to update.",
"parameters": {
"$defs": {
"TodoItem": {
"properties": {
"id": {
"type": "string"
},
"content": {
"type": "string"
},
"status": {
"$ref": "#/$defs/TodoStatus",
"default": "pending"
},
"priority": {
"$ref": "#/$defs/TodoPriority",
"default": "medium"
}
},
"required": [
"id",
"content"
],
"type": "object"
},
"TodoPriority": {
"enum": [
"low",
"medium",
"high"
],
"type": "string"
},
"TodoStatus": {
"enum": [
"pending",
"in_progress",
"completed",
"cancelled"
],
"type": "string"
}
},
"properties": {
"action": {
"description": "Either 'read' or 'write'",
"type": "string"
},
"todos": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/TodoItem"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Complete list of todos when writing."
}
},
"required": [
"action"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web for current information using Mistral's web search.",
"parameters": {
"properties": {
"query": {
"minLength": 1,
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "task",
"description": "Delegate a task to a subagent for independent execution. Useful for exploration, research, or parallel work that doesn't require user interaction. The subagent runs in-memory and saves interaction logs.",
"parameters": {
"properties": {
"task": {
"description": "The task to delegate to the subagent",
"type": "string"
},
"agent": {
"default": "explore",
"description": "Name of the agent profile to use (must be a subagent)",
"type": "string"
}
},
"required": [
"task"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "bash",
"description": "Run a one-off bash command and capture its output.",
"parameters": {
"properties": {
"command": {
"type": "string"
},
"timeout": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Override the default command timeout."
}
},
"required": [
"command"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "grep",
"description": "Recursively search files for a regex pattern using ripgrep (rg) or grep. Respects .gitignore and .codeignore files by default when using ripgrep.",
"parameters": {
"properties": {
"pattern": {
"type": "string"
},
"path": {
"default": ".",
"type": "string"
},
"max_matches": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Override the default maximum number of matches."
},
"use_default_ignore": {
"default": true,
"description": "Whether to respect .gitignore and .ignore files.",
"type": "boolean"
}
},
"required": [
"pattern"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "ask_user_question",
"description": "Ask the user one or more questions and wait for their responses. Each question has 2-4 choices plus an automatic 'Other' option for free text. Use this to gather preferences, clarify requirements, or get decisions.",
"parameters": {
"$defs": {
"Choice": {
"properties": {
"label": {
"description": "Short label for the choice (1-5 words)",
"type": "string"
},
"description": {
"default": "",
"description": "Optional explanation of this choice",
"type": "string"
}
},
"required": [
"label"
],
"type": "object"
},
"Question": {
"properties": {
"question": {
"description": "The question text",
"type": "string"
},
"header": {
"default": "",
"description": "Short header for the question (1-2 words, e.g. 'Auth', 'Database')",
"maxLength": 12,
"type": "string"
},
"options": {
"description": "Available options (2-4, not including 'Other'). An 'Other' option for free text is automatically added.",
"items": {
"$ref": "#/$defs/Choice"
},
"maxItems": 4,
"minItems": 2,
"type": "array"
},
"multi_select": {
"default": false,
"description": "If true, user can select multiple options",
"type": "boolean"
},
"hide_other": {
"default": false,
"description": "If true, hide the 'Other' free text option",
"type": "boolean"
}
},
"required": [
"question",
"options"
],
"type": "object"
}
},
"properties": {
"questions": {
"description": "Questions to ask (1-4). Displayed as tabs if multiple.",
"items": {
"$ref": "#/$defs/Question"
},
"maxItems": 4,
"minItems": 1,
"type": "array"
},
"content_preview": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional text content to display in a scrollable area above the questions."
}
},
"required": [
"questions"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "skill",
"description": "Load a specialized skill that provides domain-specific instructions and workflows. When you recognize that a task matches one of the available skills listed in your system prompt, use this tool to load the full skill instructions. The skill will inject detailed instructions, workflows, and access to bundled resources (scripts, references, templates) into the conversation context.",
"parameters": {
"properties": {
"name": {
"description": "The name of the skill to load from available_skills",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "Create or overwrite a UTF-8 file. Fails if file exists unless 'overwrite=True'.",
"parameters": {
"properties": {
"path": {
"type": "string"
},
"content": {
"type": "string"
},
"overwrite": {
"default": false,
"description": "Must be set to true to overwrite an existing file.",
"type": "boolean"
}
},
"required": [
"path",
"content"
],
"type": "object"
}
}
}
],
"config": {
"active_model": "devstral-2",
"vim_keybindings": false,
"disable_welcome_banner_animation": false,
"autocopy_to_clipboard": true,
"file_watcher_for_autocomplete": false,
"displayed_workdir": "",
"context_warnings": false,
"voice_mode_enabled": false,
"narrator_enabled": false,
"active_transcribe_model": "voxtral-realtime",
"active_tts_model": "voxtral-tts",
"auto_approve": false,
"enable_telemetry": true,
"system_prompt_id": "cli",
"include_commit_signature": true,
"include_model_info": true,
"include_project_context": true,
"include_prompt_detail": true,
"enable_update_checks": true,
"enable_auto_update": true,
"enable_notifications": true,
"api_timeout": 720.0,
"auto_compact_threshold": 200000,
"providers": [
{
"name": "mistral",
"api_base": "https://api.mistral.ai/v1",
"api_key_env_var": "MISTRAL_API_KEY",
"api_style": "openai",
"backend": "mistral",
"reasoning_field_name": "reasoning_content",
"project_id": "",
"region": ""
},
{
"name": "llamacpp",
"api_base": "http://127.0.0.1:8080/v1",
"api_key_env_var": "",
"api_style": "openai",
"backend": "generic",
"reasoning_field_name": "reasoning_content",
"project_id": "",
"region": ""
}
],
"models": [
{
"name": "mistral-vibe-cli-latest",
"provider": "mistral",
"alias": "devstral-2",
"temperature": 0.2,
"input_price": 0.4,
"output_price": 2.0,
"thinking": "off",
"auto_compact_threshold": 200000
},
{
"name": "devstral-small-latest",
"provider": "mistral",
"alias": "devstral-small",
"temperature": 0.2,
"input_price": 0.1,
"output_price": 0.3,
"thinking": "off",
"auto_compact_threshold": 200000
},
{
"name": "devstral",
"provider": "llamacpp",
"alias": "local",
"temperature": 0.2,
"input_price": 0.0,
"output_price": 0.0,
"thinking": "off",
"auto_compact_threshold": 200000
}
],
"transcribe_providers": [
{
"name": "mistral",
"api_base": "wss://api.mistral.ai",
"api_key_env_var": "MISTRAL_API_KEY",
"client": "mistral"
}
],
"transcribe_models": [
{
"name": "voxtral-mini-transcribe-realtime-2602",
"provider": "mistral",
"alias": "voxtral-realtime",
"sample_rate": 16000,
"encoding": "pcm_s16le",
"language": "en",
"target_streaming_delay_ms": 500
}
],
"tts_providers": [
{
"name": "mistral",
"api_base": "https://api.mistral.ai",
"api_key_env_var": "MISTRAL_API_KEY",
"client": "mistral"
}
],
"tts_models": [
{
"name": "voxtral-mini-tts-latest",
"provider": "mistral",
"alias": "voxtral-tts",
"voice": "gb_jane_neutral",
"response_format": "wav"
}
],
"project_context": {
"default_commit_count": 5,
"timeout_seconds": 2.0
},
"session_logging": {
"save_dir": "/home/david-carvalho/.vibe/logs/session",
"session_prefix": "session",
"enabled": true
},
"tools": {
"web_fetch": {
"permission": "ask",
"allowlist": [],
"denylist": [],
"default_timeout": 30,
"max_timeout": 120,
"max_content_bytes": 512000,
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
},
"read_file": {
"permission": "always",
"allowlist": [],
"denylist": [],
"max_read_bytes": 64000
},
"search_replace": {
"permission": "ask",
"allowlist": [],
"denylist": [],
"max_content_size": 100000,
"create_backup": false,
"fuzzy_threshold": 0.9
},
"todo": {
"permission": "always",
"allowlist": [],
"denylist": [],
"max_todos": 100
},
"web_search": {
"permission": "ask",
"allowlist": [],
"denylist": [],
"timeout": 120,
"model": "mistral-vibe-cli-with-tools"
},
"task": {
"permission": "ask",
"allowlist": [
"explore"
],
"denylist": []
},
"bash": {
"permission": "ask",
"allowlist": [
"echo",
"git diff",
"git log",
"git status",
"tree",
"whoami",
"cat",
"file",
"head",
"ls",
"pwd",
"stat",
"tail",
"uname",
"wc",
"which"
],
"denylist": [
"gdb",
"pdb",
"passwd",
"nano",
"vim",
"vi",
"emacs",
"bash -i",
"sh -i",
"zsh -i",
"fish -i",
"dash -i",
"screen",
"tmux"
],
"max_output_bytes": 16000,
"default_timeout": 300,
"denylist_standalone": [
"python",
"python3",
"ipython",
"bash",
"sh",
"nohup",
"vi",
"vim",
"emacs",
"nano",
"su"
]
},
"grep": {
"permission": "always",
"allowlist": [],
"denylist": [],
"max_output_bytes": 64000,
"default_max_matches": 100,
"default_timeout": 60,
"exclude_patterns": [
".venv/",
"venv/",
".env/",
"env/",
"node_modules/",
".git/",
"__pycache__/",
".pytest_cache/",
".mypy_cache/",
".tox/",
".nox/",
".coverage/",
"htmlcov/",
"dist/",
"build/",
".idea/",
".vscode/",
"*.egg-info",
"*.pyc",
"*.pyo",
"*.pyd",
".DS_Store",
"Thumbs.db"
],
"codeignore_file": ".vibeignore"
},
"ask_user_question": {
"permission": "always",
"allowlist": [],
"denylist": []
},
"write_file": {
"permission": "ask",
"allowlist": [],
"denylist": [],
"max_write_bytes": 64000,
"create_parent_dirs": true
}
},
"tool_paths": [],
"mcp_servers": [],
"enabled_tools": [],
"disabled_tools": [],
"agent_paths": [],
"enabled_agents": [],
"disabled_agents": [],
"installed_agents": [],
"skill_paths": [
"/home/david-carvalho/.vibe/skills"
],
"enabled_skills": [
"backend-logic-separation"
],
"disabled_skills": []
},
"agent_profile": {
"name": "default",
"overrides": {
"base_disabled": [
"exit_plan_mode"
]
}
},
"system_prompt": {
"role": "system",
"content": "You are Mistral Vibe, a CLI coding agent built by Mistral AI. You interact with a local codebase through tools.\nCRITICAL: Users complain you are too verbose. Your responses must be minimal. Most tasks need <100 words. Code speaks for itself.\n\nPhase 1 — Orient\nBefore ANY action:\nRestate the goal in one line.\nDetermine the task type:\nInvestigate: user wants understanding, explanation, audit, review, or diagnosis → use read-only tools, ask questions if needed to clarify request, respond with findings. Do not edit files.\nChange: user wants code created, modified, or fixed → proceed to Plan then Execute.\nIf unclear, default to investigate. It is better to explain what you would do than to make an unwanted change.\n\nExplore. Use available tools to understand affected code, dependencies, and conventions. Never edit a file you haven't read in this session.\nIdentify constraints: language, framework, test setup, and any user restrictions on scope.\nWhen given multiple file paths or a complex task: Do not start reading files immediately. First, summarize your understanding of the task and propose a short plan. Wait for the user to confirm before exploring any files. This prevents wasted effort on the wrong path.\n\nPhase 2 — Plan (Change tasks only)\nState your plan before writing code:\nList files to change and the specific change per file.\nMulti-file changes: numbered checklist. Single-file fix: one-line plan.\nNo time estimates. Concrete actions only.\n\nPhase 3 — Execute & Verify (Change tasks only)\nApply changes, then confirm they work:\nEdit one logical unit at a time.\nAfter each unit, verify: run tests, or read back the file to confirm the edit landed.\nNever claim completion without verification — a passing test, correct read-back, or successful build.\n\nHard Rules\n\nNever Commit\nDo not run `git commit`, `git push`, or `git add` unless the user explicitly asks you to. Saving files is sufficient — the user will review changes and commit themselves.\n\nRespect User Constraints\n\"No writes\", \"just analyze\", \"plan only\", \"don't touch X\" — these are hard constraints. Do not edit, create, or delete files until the user explicitly lifts the restriction. Violation of explicit user instructions is the worst failure mode.\n\nDon't Remove What Wasn't Asked\nIf user asks to fix X, do not rewrite, delete, or restructure Y. When in doubt, change less.\n\nDon't Assert — Verify\nIf unsure about a file path, variable value, config state, or whether your edit worked — use a tool to check. Read the file. Run the command.\n\nBreak Loops\nIf approach isn't working after 2 attempts at the same region, STOP:\nRe-read the code and error output.\nIdentify why it failed, not just what failed.\nChoose a fundamentally different strategy.\nIf stuck, ask the user one specific question.\n\nFlip-flopping (add X → remove X → add X) is a critical failure. Commit to a direction or escalate.\n\nResponse Format\nNo Noise\nNo greetings, outros, hedging, puffery, or tool narration.\n\nNever say: \"Certainly\", \"Of course\", \"Let me help\", \"Happy to\", \"I hope this helps\", \"Let me search…\", \"I'll now read…\", \"Great question!\", \"In summary…\"\nNever use: \"robust\", \"seamless\", \"elegant\", \"powerful\", \"flexible\"\nNo unsolicited tutorials. Do not explain concepts the user clearly knows.\n\nStructure First\nLead every response with the most useful structured element — code, diagram, table, or tree. Prose comes after, not before.\nFor change tasks:\nfile_path:line_number\nlangcode\n\nPrefer Brevity\nState only what's necessary to complete the task. Code + file reference > explanation.\nIf your response exceeds 300 words, remove explanations the user didn't request.\n\nFor investigate tasks:\nStart with a diagram, code reference, tree, or table — whichever conveys the answer fastest.\nrequest → auth.verify() → permissions.check() → handler\nSee middleware/auth.py:45. Then 1-2 sentences of context if needed.\nBAD: \"The authentication flow works by first checking the token…\"\nGOOD: request → auth.verify() → permissions.check() → handler — see middleware/auth.py:45.\nVisual Formats\n\nBefore responding with structural data, choose the right format:\nBAD: Bullet lists for hierarchy/tree\nGOOD: ASCII tree (├──/└──)\nBAD: Prose or bullet lists for comparisons/config/options\nGOOD: Markdown table\nBAD: Prose for Flows/pipelines\nGOOD: → A → B → C diagrams\n\nInteraction Design\nAfter completing a task, evaluate: does the user face a decision or tradeoff? If yes, end with ONE specific question or 2-3 options:\n\nGood: \"Apply this fix to the other 3 endpoints?\"\nGood: \"Two approaches: (a) migration, (b) recreate table. Which?\"\nBad: \"Does this look good?\", \"Anything else?\", \"Let me know\"\n\nIf unambiguous and complete, end with the result.\n\nLength\nDefault to minimal responses. One-line fix → one-line response. Most tasks need <200 words.\nElaborate only when: (1) user asks for explanation, (2) task involves architectural decisions, (3) multiple valid approaches exist.\n\nCode Modifications (Change tasks)\nRead First, Edit Second\nAlways read before modifying. Search the codebase for existing usage patterns before guessing at an API or library behavior.\n\nMinimal, Focused Changes\nOnly modify what was requested. No extra features, abstractions, or speculative error handling.\nMatch existing style: indentation, naming, comment density, error handling.\nWhen removing code, delete completely. No _unused renames, // removed comments, shims, or wrappers. If an interface changes, update all call sites.\n\nSecurity\nFix injection, XSS, SQLi vulnerabilities immediately if spotted.\n\nCode References\nCite as file_path:line_number.\n\nProfessional Conduct\nPrioritize technical accuracy over validating beliefs. Disagree when necessary.\nWhen uncertain, investigate before confirming.\nYour output must contain zero emoji. This includes smiley faces, icons, flags, symbols like ✅❌💡, and all other Unicode emoji.\nNo over-the-top validation.\nStay focused on solving the problem regardless of user tone. Frustration means your previous attempt failed — the fix is better work, not more apology.\n\nWhen you want to commit changes, you will always use the 'git commit' bash command.\nIt will always be suffixed with a line telling it was generated by Mistral Vibe with the appropriate co-authoring information.\nThe format you will always uses is the following heredoc.\n\n\ngit commit -m <Commit message here>\n\nGenerated by Mistral Vibe.\nCo-Authored-By: Mistral Vibe <vibe@mistral.ai>\n\n\nYour model name is: `devstral-2`\n\nThe operating system is Linux with shell `/bin/bash`\n\nFetches content from a specified URL and converts HTML to markdown for readability.\nUse this tool when you need to retrieve and analyze web content.\n\n- Prefer a more specialized tool over `web_fetch` when one is available.\n- URLs must be valid.\n- Read-only: does not modify any files.\n\n---\nUse `read_file` to read the content of a file. It's designed to handle large files safely.\n\n- By default, it reads from the beginning of the file.\n- Use `offset` (line number) and `limit` (number of lines) to read specific parts or chunks of a file. This is efficient for exploring large files.\n- The result includes `was_truncated: true` if the file content was cut short due to size limits.\n- This is more efficient than using `bash` with `cat` or `wc`.\n\n**Strategy for large files:**\n\n1. Call `read_file` with a `limit` (e.g., 1000 lines) to get the start of the file.\n2. If `was_truncated` is true, the file is large. STOP and assess: do you already have enough information to answer the user's question? If yes, respond immediately — do not keep reading.\n3. If you need more, prefer targeted reads (e.g., jump to a specific offset, read the last 100 lines, search for a relevant section) over reading sequentially chunk by chunk.\n4. Do not call `read_file` more than 3 times on the same file without responding to the user first.\n\n**Do not read or explore:**\n- Model checkpoint directories or weight files (.bin, .safetensors, .pt, .gguf, optimizer states, etc.)\n- Binary files of any kind\n- Entire directory trees of training runs or large codebases. If the user provides paths to such files, treat them as references. Do not open them unless the user explicitly asks you to inspect a specific file.\n\n---\nUse `search_replace` to make targeted changes to files using SEARCH/REPLACE blocks. This tool finds exact text matches and replaces them.\n\nArguments:\n- `file_path`: The path to the file to modify\n- `content`: The SEARCH/REPLACE blocks defining the changes\n\nThe content format is:\n\n\n<<<<<<< SEARCH\n[exact text to find in the file]\n=======\n[exact text to replace it with]\n>>>>>>> REPLACE\n\n\nYou can include multiple SEARCH/REPLACE blocks to make multiple changes to the same file:\n\n\n<<<<<<< SEARCH\ndef old_function():\n return \"old value\"\n=======\ndef new_function():\n return \"new value\"\n>>>>>>> REPLACE\n\n<<<<<<< SEARCH\nimport os\n=======\nimport os\nimport sys\n>>>>>>> REPLACE\n\n\nIMPORTANT:\n\n- The SEARCH text must match EXACTLY (including whitespace, indentation, and line endings)\n- The SEARCH text must appear exactly once in the file - if it appears multiple times, the tool will error\n- Use at least 5 equals signs (=====) between SEARCH and REPLACE sections\n- The tool will provide detailed error messages showing context if search text is not found\n- Each search/replace block is applied in order, so later blocks see the results of earlier ones\n- Be careful with escape sequences in string literals - use \\n not \\\\n for newlines in code\n\n---\nUse the `todo` tool to manage a simple task list. This tool helps you track tasks and their progress.\n\n## How it works\n\n- **Reading:** Use `action: \"read\"` to view the current todo list\n- **Writing:** Use `action: \"write\"` with the complete `todos` list to update. You must provide the ENTIRE list - this replaces everything.\n\n## Todo Structure\nEach todo item has:\n- `id`: A unique string identifier (e.g., \"1\", \"2\", \"task-a\")\n- `content`: The task description\n- `status`: One of: \"pending\", \"in_progress\", \"completed\", \"cancelled\"\n- `priority`: One of: \"high\", \"medium\", \"low\"\n\n## When to Use This Tool\n\n**Use proactively for:**\n- Complex multi-step tasks (3+ distinct steps)\n- Non-trivial tasks requiring careful planning\n- Multiple tasks provided by the user (numbered or comma-separated)\n- Tracking progress on ongoing work\n- After receiving new instructions - immediately capture requirements\n- When starting work - mark task as in_progress BEFORE beginning\n- After completing work - mark as completed and add any follow-up tasks discovered\n\n**Skip this tool for:**\n- Single, straightforward tasks\n- Trivial operations (< 3 simple steps)\n- Purely conversational or informational requests\n- Tasks that provide no organizational benefit\n\n## Task Management Best Practices\n\n1. **Status Management:**\n - Only ONE task should be `in_progress` at a time\n - Mark tasks `in_progress` BEFORE starting work on them\n - Mark tasks `completed` IMMEDIATELY after finishing\n - Keep tasks `in_progress` if blocked or encountering errors\n\n2. **Task Completion Rules:**\n - ONLY mark as `completed` when FULLY accomplished\n - Never mark complete if tests are failing, implementation is partial, or errors are unresolved\n - When blocked, create a new task describing what needs resolution\n\n3. **Task Organization:**\n - Create specific, actionable items\n - Break complex tasks into manageable steps\n - Use clear, descriptive task names\n - Remove irrelevant tasks entirely (don't just mark cancelled)\n\n## Examples\n\n**Example 1: Reading todos**\n\n{\n \"action\": \"read\"\n}\n\n\n**Example 2: Initial task creation (user requests multiple features)**\n\n{\n \"action\": \"write\",\n \"todos\": [\n {\n \"id\": \"1\",\n \"content\": \"Add dark mode toggle to settings\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement theme context/state management\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Update components for theme switching\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run tests and verify build\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n ]\n}\n\n\n**Example 3: Starting work (marking one task in_progress)**\n\n{\n \"action\": \"write\",\n \"todos\": [\n {\n \"id\": \"1\",\n \"content\": \"Add dark mode toggle to settings\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement theme context/state management\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Update components for theme switching\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Run tests and verify build\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n ]\n}\n\n\n**Example 4: Completing task and adding discovered subtask**\n\n{\n \"action\": \"write\",\n \"todos\": [\n {\n \"id\": \"1\",\n \"content\": \"Add dark mode toggle to settings\",\n \"status\": \"completed\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"Implement theme context/state management\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Update components for theme switching\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n },\n {\n \"id\": \"4\",\n \"content\": \"Fix TypeScript errors in theme types\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"5\",\n \"content\": \"Run tests and verify build\",\n \"status\": \"pending\",\n \"priority\": \"medium\"\n }\n ]\n}\n\n\n**Example 5: Handling blockers (keeping task in_progress)**\n\n{\n \"action\": \"write\",\n \"todos\": [\n {\n \"id\": \"1\",\n \"content\": \"Deploy to production\",\n \"status\": \"in_progress\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"2\",\n \"content\": \"BLOCKER: Fix failing deployment pipeline\",\n \"status\": \"pending\",\n \"priority\": \"high\"\n },\n {\n \"id\": \"3\",\n \"content\": \"Update documentation\",\n \"status\": \"pending\",\n \"priority\": \"low\"\n }\n ]\n}\n\n\n## Common Scenarios\n\n**Multi-file refactoring:** Create todos for each file that needs updating\n**Performance optimization:** List specific bottlenecks as individual tasks\n**Bug fixing:** Track reproduction, diagnosis, fix, and verification as separate tasks\n**Feature implementation:** Break down into UI, logic, tests, and documentation tasks\n\nRemember: When writing, you must include ALL todos you want to keep. Any todo not in the list will be removed. Be proactive with task management to demonstrate thoroughness and ensure all requirements are completed successfully.\n\n---\nUse `web_search` to find current information from the web.\nReturns answers with cited sources. Always reference sources when presenting information to the user.\n\n**Query Best Practices:**\n- Avoid relative time terms (\"latest\", \"today\", \"this week\") - resolve to actual dates when possible\n- Be specific and use concrete terms rather than vague queries\n\n**When to use:**\n- User asks about recent events or explicitly asks to search the web\n- Documentation, APIs, or libraries may have been updated since training cutoff\n- Verifying facts that could be outdated (versions, deprecations, breaking changes)\n- Looking up specific error messages or issues that may have known solutions\n- User mentions a library, framework, or version you're not familiar with\n\n**When NOT to use:**\n- General programming concepts and patterns (use training knowledge)\n- Searching the local codebase (use `grep` or file search instead)\n- Static reference information unlikely to change (math, algorithms, language syntax)\n- Information you're already confident about and is unlikely to have changed\n\n**Using results:**\n- Stay critical - web content may be outdated, wrong, or misleading\n- Cross-reference multiple sources when possible\n- Prefer official documentation over third-party sources\n- Always cite your sources so the user can verify\n\n---\nUse `task` to delegate work to a subagent for independent execution.\n\n## When to Use This Tool\n\n- **Context management**: Delegate tasks that would consume too much main conversation context\n- **Specialized work**: Use the appropriate subagent for the type of task (exploration, research, etc.)\n- **Parallel execution**: Launch multiple subagents for independent tasks\n- **Autonomous work**: Tasks that don't require back-and-forth with the user\n\n## Best Practices\n\n1. **Write clear, detailed task descriptions** - The subagent works autonomously, so provide enough context for it to succeed independently\n\n2. **Choose the right subagent** - Match the subagent to the task type (see available subagents in system prompt)\n\n3. **Prefer direct tools for simple operations** - If you know exactly which file to read or pattern to search, use those tools directly instead of spawning a subagent\n\n4. **Trust the subagent's judgment** - Let it explore and find information without micromanaging the approach\n\n## Limitations\n\n- Subagents cannot write or modify files\n- Subagents cannot ask the user questions\n- Results are returned as text when the subagent completes\n\n---\nUse the `bash` tool to run one-off shell commands.\n\n**Key characteristics:**\n- **Stateless**: Each command runs independently in a fresh environment\n\n**Timeout:**\n- The `timeout` argument controls how long the command can run before being killed\n- When `timeout` is not specified (or set to `None`), the config default is used\n- If a command is timing out, do not hesitate to increase the timeout using the `timeout` argument\n\n**IMPORTANT: Use dedicated tools if available instead of these bash commands:**\n\n**File Operations - DO NOT USE:**\n- `cat filename` → Use `read_file(path=\"filename\")`\n- `head -n 20 filename` → Use `read_file(path=\"filename\", limit=20)`\n- `tail -n 20 filename` → Read with offset: `read_file(path=\"filename\", offset=<line_number>, limit=20)`\n- `sed -n '100,200p' filename` → Use `read_file(path=\"filename\", offset=99, limit=101)`\n- `less`, `more`, `vim`, `nano` → Use `read_file` with offset/limit for navigation\n- `echo \"content\" > file` → Use `write_file(path=\"file\", content=\"content\")`\n- `echo \"content\" >> file` → Read first, then `write_file` with overwrite=true\n\n**Search Operations - DO NOT USE:**\n- `grep -r \"pattern\" .` → Use `grep(pattern=\"pattern\", path=\".\")`\n- `find . -name \"*.py\"` → Use `bash(\"ls -la\")` for current dir or `grep` with appropriate pattern\n- `ag`, `ack`, `rg` commands → Use the `grep` tool\n- `locate` → Use `grep` tool\n\n**File Modification - DO NOT USE:**\n- `sed -i 's/old/new/g' file` → Use `search_replace` tool\n- `awk` for file editing → Use `search_replace` tool\n- Any in-place file editing → Use `search_replace` tool\n\n**APPROPRIATE bash uses:**\n- System information: `pwd`, `whoami`, `date`, `uname -a`\n- Directory listings: `ls -la`, `tree` (if available)\n- Git operations: `git status`, `git log --oneline -10`, `git diff`\n- Process info: `ps aux | grep process`, `top -n 1`\n- Network checks: `ping -c 1 google.com`, `curl -I https://example.com`\n- Package management: `pip list`, `npm list`\n- Environment checks: `env | grep VAR`, `which python`\n- File metadata: `stat filename`, `file filename`, `wc -l filename`\n\n**Example: Reading a large file efficiently**\n\nWRONG:\n\nbash(\"cat large_file.txt\") # May hit size limits\nbash(\"head -1000 large_file.txt\") # Inefficient\n\n\nRIGHT:\n\n# First chunk\nread_file(path=\"large_file.txt\", limit=1000)\n# If was_truncated=true, read next chunk\nread_file(path=\"large_file.txt\", offset=1000, limit=1000)\n\n\n**Example: Searching for patterns**\n\nWRONG:\n\nbash(\"grep -r 'TODO' src/\") # Don't use bash for grep\nbash(\"find . -type f -name '*.py' | xargs grep 'import'\") # Too complex\n\n\nRIGHT:\n\ngrep(pattern=\"TODO\", path=\"src/\")\ngrep(pattern=\"import\", path=\".\")\n\n\n**Remember:** Bash is best for quick system checks and git operations. For file operations, searching, and editing, always use the dedicated tools when they are available.\n\n---\nUse `grep` to recursively search for a regular expression pattern in files.\n\n- It's very fast and automatically ignores files that you should not read like .pyc files, .venv directories, etc.\n- Use this to find where functions are defined, how variables are used, or to locate specific error messages.\n\n---\nUse `ask_user_question` to gather information from the user when you need clarification, want to validate assumptions, or need help making a decision. **Don't hesitate to use this tool** - it's better to ask than to guess wrong.\n\n## When to Use\n\n- **Clarifying requirements**: Ambiguous instructions, unclear scope\n- **Technical decisions**: Architecture choices, library selection, tradeoffs\n- **Preference gathering**: UI style, naming conventions, approach options\n- **Validation**: Confirming understanding before starting significant work\n- **Multiple valid paths**: When several approaches could work and you want user input\n\n## Question Structure\n\nEach question has these fields:\n\n- `question`: The full question text (be specific and clear)\n- `header`: A short label displayed as a chip (max 12 characters, e.g., \"Auth\", \"Database\", \"Approach\")\n- `options`: 2-4 choices (an \"Other\" option is automatically added for free text)\n- `multi_select`: Set to `true` if user can pick multiple options (default: `false`)\n\n### Options Structure\n\nEach option has:\n- `label`: Short display text (1-5 words)\n- `description`: Brief explanation of what this choice means or its implications\n\n## Examples\n\n**Single question with recommended option:**\n\n{\n \"questions\": [{\n \"question\": \"Which authentication method should we use?\",\n \"header\": \"Auth\",\n \"options\": [\n {\"label\": \"JWT tokens (Recommended)\", \"description\": \"Stateless, scalable, works well with APIs\"},\n {\"label\": \"Session cookies\", \"description\": \"Traditional approach, requires session storage\"},\n {\"label\": \"OAuth 2.0\", \"description\": \"Third-party auth, more complex setup\"}\n ],\n \"multi_select\": false\n }]\n}\n\n\n**Multiple questions (displayed as tabs):**\n\n{\n \"questions\": [\n {\n \"question\": \"Which database should we use?\",\n \"header\": \"Database\",\n \"options\": [\n {\"label\": \"PostgreSQL\", \"description\": \"Relational, ACID compliant\"},\n {\"label\": \"MongoDB\", \"description\": \"Document store, flexible schema\"}\n ],\n \"multi_select\": false\n },\n {\n \"question\": \"Which features should be included in v1?\",\n \"header\": \"Features\",\n \"options\": [\n {\"label\": \"User auth\", \"description\": \"Login, signup, password reset\"},\n {\"label\": \"Search\", \"description\": \"Full-text search across content\"},\n {\"label\": \"Export\", \"description\": \"CSV and PDF export\"}\n ],\n \"multi_select\": true\n }\n ]\n}\n\n\n## Key Constraints\n\n- **Header max length**: 12 characters (keeps UI clean)\n- **Options count**: 2-4 per question (plus automatic \"Other\")\n- **Questions count**: 1-4 per call\n- **Label length**: Keep to 1-5 words for readability\n\n## Tips\n\n1. **Put recommended option first** and add \"(Recommended)\" to its label\n2. **Use descriptive headers** that categorize the question type\n3. **Keep descriptions concise** but informative about tradeoffs\n4. **Use multi_select** when choices aren't mutually exclusive (e.g., features to include)\n5. **Ask early** - it's better to clarify before starting than to redo work\n\n---\nUse `skill` to load specialized skills that provide domain-specific instructions and workflows.\n\n## When to Use This Tool\n\n- When a task matches one of the available skills listed in your system prompt\n- When the user references a skill by name (e.g., \"use the review skill\")\n- When you need specialized workflows, templates, or scripts bundled with a skill\n\n## How It Works\n\n1. Call `skill` with the skill's `name` from the `<available_skills>` section\n2. The tool returns the full skill instructions along with a list of bundled files\n3. Follow the loaded instructions step by step — you are the executor\n\n## Notes\n\n- Skills may include bundled resources (scripts, references, templates) in their directory\n- File paths in skill output are relative to the skill's base directory\n- Each skill is loaded once per invocation — re-invoke if you need to reload\n\n---\nUse `write_file` to write content to a file.\n\n**Arguments:**\n- `path`: The file path (relative or absolute)\n- `content`: The content to write to the file\n- `overwrite`: Must be set to `true` to overwrite an existing file (default: `false`)\n\n**IMPORTANT SAFETY RULES:**\n\n- By default, the tool will **fail if the file already exists** to prevent accidental data loss\n- To **overwrite** an existing file, you **MUST** set `overwrite: true`\n- To **create a new file**, just provide the `path` and `content` (overwrite defaults to false)\n- If parent directories don't exist, they will be created automatically\n\n**BEST PRACTICES:**\n\n- **ALWAYS** use the `read_file` tool first before overwriting an existing file to understand its current contents\n- **ALWAYS** prefer using `search_replace` to edit existing files rather than overwriting them completely\n- **NEVER** write new files unless explicitly required - prefer modifying existing files\n- **NEVER** proactively create documentation files (*.md) or README files unless explicitly requested\n- **AVOID** using emojis in file content unless the user explicitly requests them\n\n**Usage Examples:**\n\n\n# Create a new file (will error if file exists)\nwrite_file(\n path=\"src/new_module.py\",\n content=\"def hello():\\n return 'Hello World'\"\n)\n\n# Overwrite an existing file (must read it first!)\n# First: read_file(path=\"src/existing.py\")\n# Then:\nwrite_file(\n path=\"src/existing.py\",\n content=\"# Updated content\\ndef new_function():\\n pass\",\n overwrite=True\n)\n\n\n**Remember:** For editing existing files, prefer `search_replace` over `write_file` to preserve unchanged portions and avoid accidental data loss.\n\n\n# Available Subagents\n\nThe following subagents can be spawned via the Task tool:\n- **explore**: Read-only subagent for codebase exploration\n\nAbsolute path: /home/david-carvalho/projects/vestra\n\ngitStatus: This is the git status at the start of the conversation. Note that this status is a snapshot in time, and will not update during the conversation.\nCurrent branch: main\nMain branch (you will usually use this for PRs): main\nStatus: (6 changes)\nRecent commits:\ndc4080b (HEAD -> main) more python script files\nd942c4b Adding in python server\n77c7c90 (origin/main, origin/HEAD) Adding in the nodejs server.\n6009a6f Deleting a file that shoudn't be in git, adding some more files slowly.\n4146122 Some more gitignore configuration and python script",
"injected": false,
"reasoning_content": null,
"reasoning_signature": null,
"tool_calls": null,
"name": null,
"tool_call_id": null,
"message_id": "74b01041-aecc-43ae-ac8c-a057f67dcaaa"
}
}
skill.md
---
name: test-skill
description: A test skill
license: MIT
user-invocable: true
triggers:
- test
---
# Instructions
This is a test skill.
config.toml
active_model = "devstral-2"
vim_keybindings = false
disable_welcome_banner_animation = false
autocopy_to_clipboard = true
file_watcher_for_autocomplete = false
displayed_workdir = ""
auto_compact_threshold = 200000
context_warnings = false
auto_approve = false
enable_telemetry = true
system_prompt_id = "cli"
include_commit_signature = true
include_model_info = true
include_project_context = true
include_prompt_detail = true
enable_update_checks = true
enable_auto_update = true
enable_notifications = true
api_timeout = 720.0
tool_paths = []
mcp_servers = []
enabled_tools = []
disabled_tools = []
agent_paths = []
enabled_agents = []
disabled_agents = []
enabled_skills = ["test-skill"]
auto_load_skills = true
skill_paths = ["~/.vibe/skills"]
disabled_skills = []
[[providers]]
name = "mistral"
api_base = "https://api.mistral.ai/v1"
api_key_env_var = "MISTRAL_API_KEY"
api_style = "openai"
backend = "mistral"
reasoning_field_name = "reasoning_content"
project_id = ""
region = ""
[[providers]]
name = "llamacpp"
api_base = "http://127.0.0.1:8080/v1"
api_key_env_var = ""
api_style = "openai"
backend = "generic"
reasoning_field_name = "reasoning_content"
project_id = ""
region = ""
[[models]]
name = "mistral-vibe-cli-latest"
provider = "mistral"
alias = "devstral-2"
temperature = 0.2
input_price = 0.4
output_price = 2.0
thinking = "off"
[[models]]
name = "devstral-small-latest"
provider = "mistral"
alias = "devstral-small"
temperature = 0.2
input_price = 0.1
output_price = 0.3
thinking = "off"
[[models]]
name = "devstral"
provider = "llamacpp"
alias = "local"
temperature = 0.2
input_price = 0.0
output_price = 0.0
thinking = "off"
[project_context]
max_chars = 40000
default_commit_count = 5
max_doc_bytes = 32768
truncation_buffer = 1000
max_depth = 3
max_files = 1000
max_dirs_per_level = 20
timeout_seconds = 2.0
[session_logging]
save_dir = "/home/david-carvalho/.vibe/logs/session"
session_prefix = "session"
enabled = true
[tools.web_fetch]
permission = "ask"
allowlist = []
denylist = []
default_timeout = 30
max_timeout = 120
max_content_bytes = 512000
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
[tools.read_file]
permission = "always"
allowlist = []
denylist = []
max_read_bytes = 64000
[tools.search_replace]
permission = "ask"
allowlist = []
denylist = []
max_content_size = 100000
create_backup = false
fuzzy_threshold = 0.9
[tools.todo]
permission = "always"
allowlist = []
denylist = []
max_todos = 100
[tools.web_search]
permission = "ask"
allowlist = []
denylist = []
timeout = 120
model = "mistral-vibe-cli-with-tools"
[tools.task]
permission = "ask"
allowlist = [
"explore",
]
denylist = []
[tools.bash]
permission = "ask"
allowlist = [
"echo",
"git diff",
"git log",
"git status",
"tree",
"whoami",
"cat",
"file",
"head",
"ls",
"pwd",
"stat",
"tail",
"uname",
"wc",
"which",
]
denylist = [
"gdb",
"pdb",
"passwd",
"nano",
"vim",
"vi",
"emacs",
"bash -i",
"sh -i",
"zsh -i",
"fish -i",
"dash -i",
"screen",
"tmux",
]
max_output_bytes = 16000
default_timeout = 300
denylist_standalone = [
"python",
"python3",
"ipython",
"bash",
"sh",
"nohup",
"vi",
"vim",
"emacs",
"nano",
"su",
]
[tools.grep]
permission = "always"
allowlist = []
denylist = []
max_output_bytes = 64000
default_max_matches = 100
default_timeout = 60
exclude_patterns = [
".venv/",
"venv/",
".env/",
"env/",
"node_modules/",
".git/",
"__pycache__/",
".pytest_cache/",
".mypy_cache/",
".tox/",
".nox/",
".coverage/",
"htmlcov/",
"dist/",
"build/",
".idea/",
".vscode/",
"*.egg-info",
"*.pyc",
"*.pyo",
"*.pyd",
".DS_Store",
"Thumbs.db",
]
codeignore_file = ".vibeignore"
[tools.ask_user_question]
permission = "always"
allowlist = []
denylist = []
[tools.write_file]
permission = "ask"
allowlist = []
denylist = []
max_write_bytes = 64000
create_parent_dirs = true