mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-16 16:16:32 +03:00
feat: add Mistral Vibe harness support (#373)
* feat: add Mistral Vibe harness support
Mistral Vibe is Mistral AI's open-source CLI coding assistant that ships an
Agent Skills system at .vibe/skills/{name}/SKILL.md with slash-command
invocation, mapping cleanly onto the existing transformer pipeline. Adds
Vibe as a 14th first-class harness:
- PROVIDER_PLACEHOLDERS entry in scripts/lib/utils.js (model, config_file
= AGENTS.md, ask_instruction, command_prefix) mirroring the Qoder shape.
- PROVIDERS entry in scripts/lib/transformers/providers.js with configDir
.vibe and frontmatterFields user-invocable, license, compatibility,
metadata, allowed-tools (Vibe docs do not document argument-hint).
- transformVibe named export in scripts/lib/transformers/index.js for
test-spy parity.
- vibe added to FILE_DOWNLOAD_PROVIDER_CONFIG_DIRS so the download
endpoint accepts /api/download/skill/vibe/* and resolves to
dist/vibe/.vibe/.
- .vibe added to PROVIDER_DIRS, PROVIDER_ALIASES, PROVIDER_DISPLAY,
PROVIDER_INPUT_ORDER, GLOBAL_HARNESS_HINTS, and the normalizeForHash
provider regex in cli/bin/commands/skills.mjs so the CLI detects
existing Vibe installs.
- docs/HARNESSES.md updated: official docs row, frontmatter support
column, directory structure row, and Last verified date bumped.
- docs/DEVELOP.md, README.md (install instructions, providers list,
Supported Tools), .github issue/PR templates, sync-generated-output
workflow, and AGENTS.md extended with Vibe.
The dynamic providers.test.js loop picks up Vibe automatically; all 160
provider tests pass including the 14 new Mistral Vibe cases. The build
regenerates dist/vibe/.vibe/skills/impeccable/ with correct frontmatter
and .vibe-substituted script paths. Generated harness output is left
unstaged per the source-first policy; the sync-generated-output workflow
(now listing .vibe) will commit it back to main after merge.
Co-Authored-By: Mistral Vibe <noreply@mistral.ai>
* Address review on Vibe harness support
Verified the Vibe claims against the docs and the mistralai/mistral-vibe
source, then tightened what the tables say.
- model placeholder: 'Mistral', not 'the model'. Vibe is Mistral's own
first-party CLI, so it belongs with gemini -> Gemini and codex -> GPT
rather than with the provider-agnostic harnesses. SKILL.src.md's one
use of {{model}} now renders 'Mistral is capable of extraordinary
work.' instead of a lowercase 'the model'.
- Docs links point at the skills page, not the product overview, matching
every other row in both tables.
- disable-model-invocation is No, not TBD. The field appears nowhere in
Vibe's source; unknown frontmatter keys are silently ignored.
- Split the directory row into project and global scopes the way the Pi
row already does. Vibe reads .vibe/skills/ and .agents/skills/ at the
project level and ~/.vibe/skills/ and ~/.agents/skills/ globally; the
global .agents dir was missing, and project .agents/skills/ was sitting
in the global column. Sources: vibe/core/paths/_local_config_files.py
and vibe/core/config/harness_files/_paths.py.
- Restored 'Last verified' to 2026-04-28 and dated the Vibe row on its
own. Only that row was checked, and this file warns against trusting
stale claims, so a blanket re-date made ten other rows look fresher
than they are.
AI assistance: written with Claude Code.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Mistral Vibe <noreply@mistral.ai>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Mistral Vibe
Paul Bakaus
Claude
parent
b906b41462
commit
83c37e453a
@@ -24,6 +24,7 @@ assignees: ''
|
||||
- [ ] Kiro
|
||||
- [ ] OpenCode
|
||||
- [ ] Qoder
|
||||
- [ ] Mistral Vibe
|
||||
- [ ] All providers
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -26,7 +26,7 @@ This repo is issue-first for outside contributions. If you are not `pbakaus` or
|
||||
- [ ] Source files updated in `source/`
|
||||
- [ ] `bun run build` ran successfully
|
||||
- [ ] `bun test` passes
|
||||
- [ ] Tested with at least one provider (Cursor / Claude Code / Gemini CLI / Codex / Copilot / Kiro / OpenCode / Qoder)
|
||||
- [ ] Tested with at least one provider (Cursor / Claude Code / Gemini CLI / Codex / Copilot / Kiro / OpenCode / Qoder / Mistral Vibe)
|
||||
- [ ] README / DEVELOP.md updated if needed
|
||||
- [ ] I reviewed the full diff myself before requesting human review
|
||||
- [ ] I disclosed any AI assistance in this PR and related commits/comments, or no AI assistance was used
|
||||
|
||||
@@ -33,6 +33,7 @@ env:
|
||||
.rovodev
|
||||
.trae
|
||||
.trae-cn
|
||||
.vibe
|
||||
plugin
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -21,7 +21,7 @@ Run `bun run build` after changing anything in `skill/`, transformer code, or us
|
||||
|
||||
## Generated Provider Output Policy
|
||||
|
||||
The root harness folders (`.agents/skills/`, `.claude/skills/`, `.cursor/skills/`, `.gemini/skills/`, `.github/skills/`, `.kiro/skills/`, `.opencode/skills/`, `.pi/skills/`, `.qoder/skills/`, `.rovodev/skills/`, `.trae*/skills/`) and `plugin/` stay tracked so `main` remains installable for direct GitHub, `npx skills`, and submodule users. They are still generated artifacts.
|
||||
The root harness folders (`.agents/skills/`, `.claude/skills/`, `.cursor/skills/`, `.gemini/skills/`, `.github/skills/`, `.kiro/skills/`, `.opencode/skills/`, `.pi/skills/`, `.qoder/skills/`, `.rovodev/skills/`, `.trae*/skills/`, `.vibe/skills/`) and `plugin/` stay tracked so `main` remains installable for direct GitHub, `npx skills`, and submodule users. They are still generated artifacts.
|
||||
|
||||
Normal development should be source-first: stage changes in `skill/`, `scripts/`, `cli/`, `site/`, `extension/`, `functions/`, and `tests/`; leave generated harness churn unstaged unless the user asked for it. After source changes land on `main`, `.github/workflows/sync-generated-output.yml` runs `bun run build:release` and commits generated provider output directly back to `main`. Treat generated harness diffs as release artifacts and keep them out of feature PRs unless they are the point of the PR.
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ git add .gitmodules .impeccable .claude .cursor
|
||||
git commit -m "Add Impeccable skills"
|
||||
```
|
||||
|
||||
Use the providers your project needs, for example `claude`, `cursor`, `gemini`, `codex`, `github`, `opencode`, `pi`, `qoder`, `trae`, `trae-cn`, or `rovo-dev`. The command links individual skill folders from `.impeccable/dist/universal/` and leaves existing real skill directories untouched unless you pass `--force`.
|
||||
Use the providers your project needs, for example `claude`, `cursor`, `gemini`, `codex`, `github`, `opencode`, `pi`, `qoder`, `trae`, `trae-cn`, `rovo-dev`, or `vibe`. The command links individual skill folders from `.impeccable/dist/universal/` and leaves existing real skill directories untouched unless you pass `--force`.
|
||||
|
||||
To update later:
|
||||
|
||||
@@ -250,6 +250,15 @@ cp -r dist/qoder/.qoder your-project/
|
||||
cp -r dist/qoder/.qoder/skills/* ~/.qoder/skills/
|
||||
```
|
||||
|
||||
**Mistral Vibe:**
|
||||
```bash
|
||||
# Project-specific
|
||||
cp -r dist/vibe/.vibe your-project/
|
||||
|
||||
# Or global (applies to all projects)
|
||||
cp -r dist/vibe/.vibe/skills/* ~/.vibe/skills/
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, every command runs through the single `/impeccable` skill:
|
||||
@@ -379,6 +388,7 @@ Full detector docs: [impeccable.style/docs/detector](https://impeccable.style/do
|
||||
- [Trae](https://trae.ai)
|
||||
- [Rovo Dev](https://www.atlassian.com/software/rovo)
|
||||
- [Qoder](https://qoder.com)
|
||||
- [Mistral Vibe](https://docs.mistral.ai/vibe/code/overview)
|
||||
|
||||
## Community & Ecosystem
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const API_BASE = 'https://impeccable.style';
|
||||
|
||||
// Provider folder names in project roots
|
||||
const PROVIDER_DIRS = ['.claude', '.cursor', '.gemini', '.agents', '.github', '.kiro', '.opencode', '.pi', '.qoder', '.trae', '.trae-cn', '.rovodev'];
|
||||
const PROVIDER_DIRS = ['.claude', '.cursor', '.gemini', '.agents', '.github', '.kiro', '.opencode', '.pi', '.qoder', '.trae', '.trae-cn', '.rovodev', '.vibe'];
|
||||
const PROVIDER_ALIASES = {
|
||||
agents: '.agents',
|
||||
claude: '.claude',
|
||||
@@ -41,6 +41,7 @@ const PROVIDER_ALIASES = {
|
||||
rovodev: '.rovodev',
|
||||
trae: '.trae',
|
||||
'trae-cn': '.trae-cn',
|
||||
vibe: '.vibe',
|
||||
};
|
||||
|
||||
const PROVIDER_DISPLAY = {
|
||||
@@ -56,8 +57,9 @@ const PROVIDER_DISPLAY = {
|
||||
'.rovodev': { name: 'Rovo Dev', input: 'rovo-dev' },
|
||||
'.trae': { name: 'Trae', input: 'trae' },
|
||||
'.trae-cn': { name: 'Trae CN', input: 'trae-cn' },
|
||||
'.vibe': { name: 'Mistral Vibe', input: 'vibe' },
|
||||
};
|
||||
const PROVIDER_INPUT_ORDER = ['claude', 'codex', 'cursor', 'gemini', 'github', 'kiro', 'opencode', 'pi', 'qoder', 'trae', 'trae-cn', 'rovo-dev'];
|
||||
const PROVIDER_INPUT_ORDER = ['claude', 'codex', 'cursor', 'gemini', 'github', 'kiro', 'opencode', 'pi', 'qoder', 'trae', 'trae-cn', 'rovo-dev', 'vibe'];
|
||||
|
||||
// Providers whose GLOBAL (home) skills dir is not `<provider>/skills`.
|
||||
// Pi discovers global skills from ~/.pi/agent/skills/; project scope
|
||||
@@ -79,6 +81,7 @@ const GLOBAL_HARNESS_HINTS = [
|
||||
{ home: '.pi', provider: '.pi' },
|
||||
{ home: '.qoder', provider: '.qoder' },
|
||||
{ home: '.rovodev', provider: '.rovodev' },
|
||||
{ home: '.vibe', provider: '.vibe' },
|
||||
];
|
||||
|
||||
// Last-resort default when nothing is detected: Claude Code + the universal
|
||||
@@ -568,7 +571,7 @@ async function copyOrExtractLocalBundle(sourceValue) {
|
||||
*/
|
||||
function normalizeForHash(content) {
|
||||
return content
|
||||
.replace(/\.(claude|cursor|agents|github|gemini|codex|kiro|opencode|pi|qoder|trae|trae-cn|rovodev)\/skills\//g, '.PROVIDER/skills/');
|
||||
.replace(/\.(claude|cursor|agents|github|gemini|codex|kiro|opencode|pi|qoder|trae|trae-cn|rovodev|vibe)\/skills\//g, '.PROVIDER/skills/');
|
||||
}
|
||||
|
||||
function hashSkillFile(filePath) {
|
||||
|
||||
@@ -9,6 +9,7 @@ export const FILE_DOWNLOAD_PROVIDER_CONFIG_DIRS = Object.freeze({
|
||||
opencode: '.opencode',
|
||||
pi: '.pi',
|
||||
qoder: '.qoder',
|
||||
vibe: '.vibe',
|
||||
});
|
||||
|
||||
export const FILE_DOWNLOAD_PROVIDERS = Object.freeze(
|
||||
|
||||
@@ -165,6 +165,7 @@ The skill-behavior suite runs three providers (claude-haiku-4-5, gpt-5.4-mini, g
|
||||
- [OpenCode Skills](https://opencode.ai/docs/skills/)
|
||||
- [Pi Skills](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/skills.md)
|
||||
- [Qoder Skills](https://docs.qoder.com/extensions/skills)
|
||||
- [Mistral Vibe Skills](https://docs.mistral.ai/vibe/code/cli/skills)
|
||||
|
||||
## Repository Structure
|
||||
|
||||
|
||||
+19
-17
@@ -3,7 +3,7 @@
|
||||
Source of truth for what each AI coding harness supports in terms of agent skills.
|
||||
Used to inform provider configs in `scripts/lib/transformers/providers.js`.
|
||||
|
||||
Last verified: 2026-04-28 (subagent landscape spot-checked 2026-06-28)
|
||||
Last verified: 2026-04-28 (subagent landscape spot-checked 2026-06-28; Mistral Vibe row verified 2026-07-16)
|
||||
|
||||
> This file is point-in-time. Capabilities move fast; verify live before relying
|
||||
> on any "only X supports Y" claim. Notably, the subagent table below lists
|
||||
@@ -24,6 +24,7 @@ Last verified: 2026-04-28 (subagent landscape spot-checked 2026-06-28)
|
||||
| Qoder | https://docs.qoder.com/extensions/skills |
|
||||
| Trae | TBD (no official skills docs found yet) |
|
||||
| Rovo Dev | https://support.atlassian.com/rovo/docs/extend-rovo-dev-cli-with-agent-skills |
|
||||
| Mistral Vibe | https://docs.mistral.ai/vibe/code/cli/skills |
|
||||
|
||||
## Spec Compliance
|
||||
|
||||
@@ -35,22 +36,22 @@ Provider-specific extensions beyond the spec: `user-invocable`, `argument-hint`,
|
||||
|
||||
Fields marked with * are spec-standard. Others are provider extensions.
|
||||
|
||||
| Field | Claude Code | Cursor | Gemini | Codex | Copilot | Kiro | OpenCode | Pi | Qoder | Rovo Dev |
|
||||
|-------|:-----------:|:------:|:------:|:-----:|:-------:|:----:|:--------:|:--:|:-----:|:--------:|
|
||||
| `name`* | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `description`* | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `license`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `compatibility`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `metadata`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `allowed-tools`* | Yes | No | Ignored | No | No | No | Yes | Yes | Yes | Yes |
|
||||
| `user-invocable` | Yes | No | No | No | Yes | No | Yes | No | Yes | Yes |
|
||||
| `argument-hint` | Yes | No | No | No | Yes | No | Yes | No | Yes | Yes |
|
||||
| `disable-model-invocation` | Yes | Yes | No | No | Yes | No | Yes | Yes | TBD | TBD |
|
||||
| `model` | Yes | No | No | No | No | No | Yes | No | No | No |
|
||||
| `effort` | Yes | No | No | No | No | No | No | No | No | No |
|
||||
| `context` | Yes | No | No | No | No | No | No | No | No | No |
|
||||
| `agent` | Yes | No | No | No | No | No | Yes | No | No | No |
|
||||
| `hooks` | Yes | No | No | Yes | No | No | No | No | No | No |
|
||||
| Field | Claude Code | Cursor | Gemini | Codex | Copilot | Kiro | OpenCode | Pi | Qoder | Rovo Dev | Mistral Vibe |
|
||||
|-------|:-----------:|:------:|:------:|:-----:|:-------:|:----:|:--------:|:--:|:-----:|:--------:|:------------:|
|
||||
| `name`* | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `description`* | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `license`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `compatibility`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `metadata`* | Yes | Yes | Ignored | No | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| `allowed-tools`* | Yes | No | Ignored | No | No | No | Yes | Yes | Yes | Yes | Yes |
|
||||
| `user-invocable` | Yes | No | No | No | Yes | No | Yes | No | Yes | Yes | Yes |
|
||||
| `argument-hint` | Yes | No | No | No | Yes | No | Yes | No | Yes | Yes | No |
|
||||
| `disable-model-invocation` | Yes | Yes | No | No | Yes | No | Yes | Yes | TBD | TBD | No |
|
||||
| `model` | Yes | No | No | No | No | No | Yes | No | No | No | No |
|
||||
| `effort` | Yes | No | No | No | No | No | No | No | No | No | No |
|
||||
| `context` | Yes | No | No | No | No | No | No | No | No | No | No |
|
||||
| `agent` | Yes | No | No | No | No | No | Yes | No | No | No | No |
|
||||
| `hooks` | Yes | No | No | Yes | No | No | No | No | No | No | No |
|
||||
|
||||
Notes:
|
||||
- Gemini CLI validates only `name` and `description`; other spec fields are parsed but ignored.
|
||||
@@ -84,6 +85,7 @@ Notes:
|
||||
| Trae China | `.trae-cn/skills/` | TBD |
|
||||
| Trae International | `.trae/skills/` | TBD |
|
||||
| Rovo Dev | `.rovodev/skills/` | `~/.rovodev/skills/` (user-level) |
|
||||
| Mistral Vibe | `.vibe/skills/` (project), `~/.vibe/skills/` (global) | `.agents/skills/` (project), `~/.agents/skills/` (global) |
|
||||
|
||||
All harnesses support the `{skill-name}/SKILL.md` directory structure with optional `reference/`, `scripts/`, and `assets/` subdirectories.
|
||||
|
||||
|
||||
@@ -15,5 +15,6 @@ export const transformOpenCode = createTransformer(PROVIDERS.opencode);
|
||||
export const transformPi = createTransformer(PROVIDERS.pi);
|
||||
export const transformQoder = createTransformer(PROVIDERS.qoder);
|
||||
export const transformRovoDev = createTransformer(PROVIDERS['rovo-dev']);
|
||||
export const transformVibe = createTransformer(PROVIDERS.vibe);
|
||||
|
||||
export { createTransformer, PROVIDERS };
|
||||
|
||||
@@ -122,4 +122,11 @@ export const PROVIDERS = {
|
||||
displayName: 'Rovo Dev',
|
||||
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
|
||||
},
|
||||
vibe: {
|
||||
provider: 'vibe',
|
||||
providerTags: ['vibe'],
|
||||
configDir: '.vibe',
|
||||
displayName: 'Mistral Vibe',
|
||||
frontmatterFields: ['user-invocable', 'license', 'compatibility', 'metadata', 'allowed-tools'],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -627,6 +627,12 @@ export const PROVIDER_PLACEHOLDERS = {
|
||||
config_file: 'AGENTS.md',
|
||||
ask_instruction: 'ask the user directly to clarify what you cannot infer.',
|
||||
command_prefix: '/'
|
||||
},
|
||||
'vibe': {
|
||||
model: 'Mistral',
|
||||
config_file: 'AGENTS.md',
|
||||
ask_instruction: 'ask the user directly to clarify what you cannot infer.',
|
||||
command_prefix: '/'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -645,6 +651,7 @@ export const PROVIDER_BLOCK_TAGS = new Set([
|
||||
'rovo-dev',
|
||||
'trae',
|
||||
'trae-cn',
|
||||
'vibe',
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user