Files
clide/.vibe/AGENTS.md
T
jpmschweitzer a5529577f2 chore(vibe): Add AGENTS.md for Mistral Vibe hybrid operation
Distills CLAUDE.md guardrails and .claude/skills/ into Vibe's
instruction hierarchy, preserving Claude Code punch.

Includes full pql skill integration for vault queries and
project planning workflow.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-28 22:18:53 +02:00

24 KiB

AGENTS.md for clide — Mistral Vibe operating as Claude Code peer

This file configures Mistral Vibe to operate in this repo with the same effectiveness as Claude Code. It distills the CLAUDE.md guardrails and all .claude/skills/ into Vibe's instruction hierarchy, preserving "Claude punch" in a hybrid workflow.


Identity

You are operating in clide — a Flutter/Dart IDE for Claude Code CLI. Your role: peer to Claude Code, not replacement. Maintain Claude's behavioral standards, tool discipline, and architectural rigor.

Primary directive: Never lose "Claude punch" — the combination of strict guardrails, CLI-first interaction, and parity between UI and CLI that defines effective operation in this repo.


Non-Negotiable Guardrails (from CLAUDE.md)

These are load-bearing. Violating any means the design is wrong, not the rule.

  • Flutter desktop is the host. No Electron, ever.
  • Single process. The Flutter app hosts everything in-process: IPC server, subsystem handlers (pane, files, editor, git, pql), extensions.
  • CLI-first, not MCP. Drive via clide <subsystem> <verb> Bash commands.
  • Dart is the core; pql fills the query gap. PTY spawning is native Dart FFI (posix_openpt + posix_spawn). pql (Go) handles vault queries.
  • Own the rendering stack. PTY, markdown, graph, canvas — all clide-owned.
  • User/Claude parity (D-6). Every CLI subcommand has a UI affordance, and every UI action has a CLI equivalent.
  • pql: wrap, don't duplicate. Clide wraps pql; never re-implements it.
  • Repo-is-the-workspace. Git repo root is the workspace.
  • Decision discipline. All architectural choices live in governance/decisions/<domain>.md as D-NNN records. Open questions as Q-NNN under governance/questions/<domain>.md. Rejected as R-NNN.
  • No pre-existing excuse. Solo-dev repo — if make test is red, fix it first, then your work. Surface blockers; don't push on top of broken state.

Tool Discipline (from CLAUDE.md)

Make targets are the entry points

Purpose Command Never call directly
Launch app make run flutter run
Static analysis make analyze flutter analyze
Format make format dart format
Fast test suite make test flutter test
Core subsystem tests make test-core underlying scripts
Accessibility tests make test-a11y underlying scripts
Integration tests make test-integration underlying scripts
Pre-push gate make push-check ci/* scripts
Setup hooks make hooks cp .githooks/* .git/hooks/
Clean make clean rm -rf build/

Shell hygiene

  • Working directory is repo root — never cd /path/to/clide or git -C
  • One command per invocation — no &&/; chaining
  • Exception: git commit -F HEREDOC for multi-line messages
  • Prefer Read/Edit/Grep tools over cat/sed/grep for file inspection

Git Workflow (from git-commit skill)

Commit message format: Conventional Commits 1.0

<type>(<scope>): <imperative subject> (<T-NNN>)

Optional body: explain WHY, not WHAT. Wrap at ~72 chars.

Co-Authored-By: Mistral Vibe <vibe@mistral.ai>

Type: feat, fix, docs, style, refactor, perf, test, build, chore

  • Use feat/fix for user-visible behavior
  • Use chore for bookkeeping (chore(plan) for pql ticket housekeeping)
  • Append ! after scope for breaking changes: feat(ipc)!: ...

Scope: Optional but preferred — subsystem: settings, vim, pty, git, plan

  • Lower-case, no spaces

Subject: ≤ 72 characters INCLUDING prefix. No emojis. No "and".

Ticket ref: Trailing (T-NNN) when work has a ticket.

Body: Explain the why. The diff shows the what. Don't restate it.

  • Hard cap: 60 words per bullet for CHANGELOG entries
  • No multi-paragraph bullets
  • No sub-headers inside bullets
  • No probe numbers, latency stats, or %-coverage deltas

Logically-separated commits

  1. Read git status + git diff first — never stage blind
  2. Group by concern, not location:
    • Bookkeeping: .gitignore, lockfiles, config
    • Documentation: README.md, ADRs, design notes
    • Tooling/skills: reusable, non-project-specific
    • Project conventions: repo's own rules
    • Feature/subsystem: one cohesive change
    • Layer changes: app, sidecar CLI, daemon, IPC, pql wrapper, canvas, git panel
  3. Prefer many small focused commits over one large mixed one
  4. Use git add <specific paths> — NEVER git add -A, git add ., git add -u
  5. Verify between commits with git status, git diff --staged, git log -1

Changelog discipline

  • Every user-visible commit must touch CHANGELOG.md under ## [Unreleased]
  • Use Keep a Changelog 1.1.0 format with sections: Added, Changed, Deprecated, Removed, Fixed, Security
  • Entries: short imperative phrases describing user-facing impact
  • 60 words hard cap per bullet — verify with make changelog-gate
  • What skips changelog: pure bookkeeping with no user-visible effect

Safety rules (reinforced)

  • Never --no-verify
  • Never --amend unless user explicitly asks
  • Never force-push to main or master
  • Always check git status before staging, git diff --staged before committing
  • Commit message via HEREDOC:
    git commit -m "$(cat <<'EOF'
    <message>
    EOF
    )"
    

What NOT to commit

  • .env, *.env.local
  • .claude/settings.local.json
  • Build artefacts: sidecar/bin/, sidecar/dist/, build/, app/.dart_tool/
  • SQLite index files: *.sqlite, *.sqlite-wal, *.sqlite-shm, *.db
  • Coverage/test output: *.out, coverage.*, *.test
  • .pql/changelog/ — auto-staged by pre-commit hook from pql DB

pql — Vault Queries + Project Planning

pql indexes a vault into SQLite and exposes structural queries plus a planning layer for decision records and tickets. One binary, two surfaces.

Precondition

command -v pql

If absent, tell the user to install from https://github.com/postmeridiem/pql/releases/latest. Don't install it yourself. Don't fall back to grep unless the user explicitly asks.

First touch: learn the vault

pql schema

Returns one row per frontmatter key with observed types and file counts. Run once per session before writing queries.


Surface 1: Vault queries

Subcommands

Command Purpose
pql files [glob] List indexed files; optional glob filter
pql tags [--sort count] Distinct tags with counts
pql backlinks <path> Files linking TO a path
pql outlinks <path> Links FROM a file
pql meta <path> Frontmatter + tags + outlinks + headings for one file
pql schema Typed frontmatter schema
pql base <name> Execute an Obsidian .base file
pql shell Interactive REPL (indexes once, then query per line)
pql query "<DSL>" SQL-derived DSL for complex queries
pql doctor Resolved vault/config/DB/index state

DSL examples

SELECT name, fm.date WHERE fm.type = 'meeting' ORDER BY fm.date DESC LIMIT 10
SELECT path WHERE 'project' IN tags ORDER BY path
SELECT name, fm.prior_job WHERE fm.type = 'council-member' ORDER BY name

Use --file q.pql or --stdin for long queries. Don't interpolate vault content into the command line.

Query cookbook

  • Files in folderpql files 'sessions/*'
  • Top tagspql tags --sort count --limit 20
  • What links to X?pql backlinks members/vaasa/persona.md
  • Date rangepql query "SELECT name, fm.date WHERE fm.date BETWEEN '2024-01-01' AND '2024-12-31'"
  • Run a Basepql base council-sessions
  • Inspect one filepql meta members/vaasa/persona.md --pretty

Surface 2: Planning (decisions + tickets)

Planning state lives in <vault>/.pql/pql.db (user-authored state, not a cache). Decision records come from the DQR tree — governance/{decisions, questions,rejected}/<domain>.md by default (D-21), configurable via dqr_dir in .pql/config.yaml or the PQL_DQR_DIR env var (env > file > default); a legacy flat decisions/ is auto-detected as a fallback. Tickets are SQLite-native.

Decision subcommands

Command Purpose
pql decisions sync [--no-style] Parse the DQR tree → upsert into pql.db; surfaces style warnings (filename, subdir-type, domain pairing/conflicts) unless --no-style
pql decisions validate [--no-style] Dry-run parse; structural errors exit non-zero, style issues warn (suppress with --no-style)
pql decisions claim <D|Q|R> <domain> "title" Print next available ID
pql decisions list [--type X] [--domain X] [--status X] List decisions
pql decisions show <id> [--with-refs] [--with-tickets] Show with joins
pql decisions coverage Confirmed decisions without tickets
pql decisions refs <id> Cross-references involving a decision

Always pql decisions sync before querying if decisions/*.md may have changed.

Ticket subcommands

Command Purpose
pql ticket new <type> "title" [--parent T-NNN] [--decision D-NNN] [--priority P] [--id-only] Create (emits T-NNN; --parent files it under an epic/story in one step; --id-only prints the bare id for tree-creation scripts)
pql ticket list [--status S] [--team T] [--assigned A] [--label L] [--under T-NNN] [--leaf] [--unblocked] List with filters. --under = recursive descendants of a ticket; --leaf = no children; --unblocked = blockers all reached a terminal status
pql ticket show <id[,id,...]> [--with-context] [--with-blockers] [--with-children] [--tree] [--depth N] Show one or more (comma-batch → array of show-trees). --with-children = direct children; --tree = nested descendant subtree + direct parent (cap with --depth N)
pql ticket status <id> <new-status> [--force] Change status. Closing (terminal status) is blocked while the ticket has open children; --force cascades that status to all not-yet-closed descendants and lists them
pql ticket statuslist List the configured status vocabulary (name, label, class, order, is_default, is_terminal) — what a UI reads to render columns
pql ticket relabel <id|record_id> [--new-label T-NNN] [--fix-prose] Reassign a ticket's friendly T-NNN label (reconcile a duplicate-label collision). Identity (record_id) and the structural graph are untouched; only the label moves. --fix-prose rewrites stale T-NNN mentions in DQR markdown
pql ticket assign <id> <agent> Set assignee
pql ticket setparent <id[,id,...]> <parent-id | none> Set (or clear with none) a ticket's parent — the hierarchy link (epic→story→task). Positional, not a flag. This is the parent/child relationship, distinct from blockers
pql ticket append <id> <text|--file|--stdin> Append to the description (blank-line separated); never round-trips existing text
pql ticket block <id> --by <other> Add a blocker (a dependency: can't start until is done) — NOT a parent/child link; use setparent or new --parent for hierarchy
pql ticket unblock <id> --from <other> Remove blocker
pql ticket team <id> <team> Set team
pql ticket label <id> add|rm <label> Manage labels
pql ticket board [--team T] Kanban board view
pql ticket refine list Tickets with empty descriptions, status-priority-sorted
pql ticket refine next [--skip N] Head of the unrefined queue with full show-tree + remaining count
pql ticket refine write <id> <json|--file|--stdin> Patch writable fields (title, description, priority, type)

Ticket types: initiative, epic, story, task, bug. The id you type and see (T-NNN) is a friendly label backed by a stable underwater record_id (also in output); two clones never collide on identity, and a duplicate label is fixed with pql ticket relabel (D-26). Statuses are a per-vault vocabulary (ticket_statuses in .pql/config.yaml), defaulting to: backlog, ready, in_progress, review, done, cancelled. Each status has a class — initial, active, review, terminal — that the engine reasons about. Run pql ticket statuslist to discover the live set. Any status can transition to any other — pql does not enforce a state machine — except that a ticket cannot reach a terminal status while it has open children (use --force to cascade the close down the subtree).

Plan subcommands

Command Purpose
pql plan status Dashboard: decision counts, open Qs, ticket summary, coverage gaps
pql plan whatsnext Next ticket to work on (active work, then the "ready" lane) with full context bundle
pql plan review Next ticket awaiting review with full context bundle
pql plan export [--stage] Append changed planning rows to .pql/changelog/<table>/<YYYY-MM>.sql (the git-tracked log of record); --stage also git adds them. Normally a no-op — mutations already write through
pql plan import [--legacy FILE] Replay .pql/changelog/ into pql.db (or one-time --legacy pql-plan.json migration from the pre-D-15 snapshot)
pql plan rebuild Drop replicated tables and replay .pql/changelog/ from scratch. Warns on stderr (changelog.ticket_id_collision) + lists collisions in the result if one ticket id was filed twice across clones

Versioning planning state

pql.db is gitignored — the durable, git-tracked artifact is .pql/changelog/ (D-15/D-16). Ticket mutations write through to the changelog synchronously, so it is always current; you never have to remember to "export". The hooks installed by pql init do the rest:

  • pre-commit stages .pql/changelog/ so it lands in the same commit as the change that produced it.
  • post-merge replays incoming changelog edits (pql plan import) and re-syncs decisions from their markdown.
  • post-checkout / post-rewrite rebuild pql.db from the changelog.

On a fresh clone, pql plan import (run automatically on first open) replays the changelog into a new pql.db. There is no pql-plan.json snapshot — that artifact is retired; pql plan export is now only a manual catch-up/reconcile.

A ticket mutation (create / status transition / any write) leaves .pql/changelog/ dirty by design — the pre-commit hook stages it onto the next git commit. This is expected, not a problem to flag. Don't narrate "the ticket won't persist until committed" on every edit; either fold the bookkeeping into a commit or trust the normal commit flow.

Planning cookbook

  • Sync and list confirmedpql decisions sync && pql decisions list --type confirmed
  • Show with refspql decisions show D-5 --with-refs --pretty
  • Read full bodypql decisions read D-5
  • Create ticketpql ticket new task "implement X" --decision D-5
  • Create ticket, capture id for a scriptid=$(pql ticket new task "implement X" --id-only) — prints just T-NNN
  • File a ticket under an epicpql ticket new bug "fix X" --parent T-276 (one step), or reparent an existing one → pql ticket setparent T-9 T-276 (clear with none). Parent = hierarchy; use block only for blocking dependencies
  • Batch closepql ticket status T-1,T-2,T-3 done
  • Full contextpql ticket show T-5 --with-context --pretty
  • Batch showpql ticket show T-1,T-2,T-3 --pretty
  • Refine next ticketpql ticket refine next --pretty, then pql ticket refine write T-N '{"description":"..."}'
  • Append a notepql ticket append T-5 "benchmarked; TTL now 5m" — blank-line separated, never overwrites; use --file note.md or --stdin for longer content
  • Subtree of an epicpql ticket show T-2 --tree --pretty — nested subtree + direct parent in ancestors; add --depth N to cap levels
  • Ready leaf work under an epicpql ticket list --under T-2 --leaf --unblocked — leaf tickets beneath T-2 whose blockers have all reached a terminal status; the batch complement to plan whatsnext
  • What's next?pql plan whatsnext --pretty
  • Review queuepql plan review --pretty
  • Coverage gapspql decisions coverage
  • Dashboardpql plan status --pretty
  • Force a changelog catch-uppql plan export (normally a no-op; mutations already write through to .pql/changelog/)

Output contract (both surfaces)

  • stdout: JSON array (default); --jsonl for one object/line; --pretty; --limit N.
  • stderr: JSON diagnostics {"level":"...","code":"pql.<phase>.<kind>","msg":"..."}.
  • Exit codes:
    • 0 — success, including zero matches (empty [] — say "no matches", not "failed")
    • 64 — bad flag
    • 65 — parse/compile error (pass stderr back)
    • 66 — vault/config not found
    • 69 — unavailable
    • 70 — internal error

Anti-patterns

  • Don't pipe to jq for simple projections — use --limit, --pretty, --jsonl.
  • Don't chain pql files + pql meta — one pql query with WHERE.
  • Don't parse errors — pass stderr diagnostics back directly.
  • Don't forget pql decisions sync before querying decisions.
  • Don't try to install or upgrade pql — instruct the user if missing.

When NOT to use

  • Body text searchgrep/rg.
  • Reading file contentsRead tool.
  • Code structure → tree-sitter / LSP.
  • Modifying vault filesWrite/Edit. pql doesn't write to vault content.

Driving clide UI via CLI (from clide skill)

Core principle: Every UI action has a CLI equivalent (D-6). Discover the live surface; don't hard-code it.

Discover capabilities

clide capabilities

Returns JSON: every registered command, split into subsystem + verb, with argument schema. This is authoritative — re-run it, don't trust remembered lists.

Slots (layout areas)

  • sidebar — left
  • workspace — center (where Claude lives)
  • context — right
  • statusbar — bottom

Observe state

# One-shot orientation
clide status

# Narrower snapshots
clide pane list
clide editor active
clide git status

Drive UI

# Open a doc in a GUI reader
clide ui open <reader> <ref>
# readers: tickets, decisions, markdown, diff
# examples:
clide ui open tickets T-123
clide ui open decisions D-456
clide ui open diff lib/src/foo.dart
clide ui open markdown docs/bar.md

# Show diff and scroll to file
clide ui diff lib/src/foo.dart

# Raise a toast
clide ui toast "message" --severity success|warning|error|info

# General: clide <subsystem> <verb> [args]
clide files list
clide editor open <path>
clide pane focus <pane-id>

Convention: If a drive verb has no live GUI, return toolError ("no live UI to drive"), not hang. Exit code conveys ok/usage/tool error. JSON on stdout.

You only see what flows through clide

Your own non-clide shell work (plain file reads, make test, git) is outside clide's view by design (D-83). Run it through clide ... if you want clide to observe it.


Testmode (from testmode skill)

ClideTestApp is a lightweight Flutter app for integration testing. Catches regressions unit tests cannot: missing binaries, broken subprocess wiring, IPC dispatch failures, extension activation order, theme parse errors.

Running

make run-testmode              # all categories, 60s timeout
make run-testmode TESTMODE_CATEGORY=toolchain
make run-testmode TESTMODE_CATEGORY=ipc
make run-testmode TESTMODE_CATEGORY=extensions
make run-testmode TESTMODE_TIMEOUT=120

Results: stdout + /tmp/clide-testmode.log Last line is machine-readable JSON: {"passed":N,"failed":M,"total":N+M,"failures":[...]}

When to run

Changed area Category Why
Toolchain, PATH, ptyc toolchain Binary resolution + exec
IPC envelope, dispatcher ipc Round-trip + error contract
Extension manifest, activate extensions Register + activate lifecycle
Theme YAML, loader extensions Theme parse is in this category
Platform config all Full rebuild validates everything
Any doubt all ~30s, cheap insurance

Interpreting output

  • [testmode] exec | ... | OK — subprocess ran, exit 0 or 1
  • [testmode] PASS | ... — assertion passed
  • [testmode] FAIL | ... — assertion failed
  • [testmode] exec | ... | EXCEPTION — binary not found or not executable
  • [testmode] exec | ... | TIMEOUT — subprocess hung

If no [testmode] lines appear, the testmode gate didn't fire — verify CLIDE_TESTMODE is set to a non-empty string.

Adding tests

All test logic in lib/test_app.dart. Pattern:

await _testExec('label', binary, ['args'], workDir);
// or
_addResult('label', boolCondition, 'detail string');

Repo Layout

lib/
  main.dart           # Flutter entry point
  app.dart            # Root layout, workspace, panels
  clide.dart          # Barrel: shared types
  src/                # Core subsystems (IPC, PTY, git, files, pql, panes)
  kernel/             # Kernel services (theme, i18n, settings, panels)
  builtin/            # Built-in extensions
  widgets/            # Custom widget primitives
  extension/          # Extension contract and registration
  lua/                # Lua runtime support

test/                 # All tests (core + widgets + goldens + a11y)
assets/               # Fonts, themes, grammars, licenses, logo
linux/, macos/, web/  # Flutter platform directories
native/               # Vendored native libs (tree-sitter, dugite)
governance/          # D/Q/R records
docs/                 # Design docs, wireframes
legacy/               # Python Textual clide v1.2 (frozen)

Dependency & Supply Chain Discipline

  • Prefer-zero-deps. Flutter-SDK widgets first; third-party needs justification
  • Exact-pinned in pubspec.yaml — no caret ranges
  • Advisories reviewed before every bump
  • pubspec.lock committed
  • Document every bundled dependency in assets/licenses.yaml:
    • name, kind, version, homepage, license, purpose
  • Adding a dep: two-step commit — artefact AND licenses.yaml entry
  • Native deps (dugite, libtree-sitter): vendored in native/, pinned by SHA

Pre-push Gate

make push-check

Runs: decisions validation + core tests + fast suite + a11y + coverage + changelog

Never bypass. If it fails, fix the underlying issue.


Session Setup

One-time setup on fresh clone:

make hooks && flutter pub get
pql init  # wires up pql skill + perms

Mistral-Specific Notes

What to preserve from Claude

  • CLI-first interaction model
  • Strict guardrails enforcement
  • Logically-separated commits
  • Changelog discipline (60-word cap)
  • pql as single source of truth for decisions/tickets
  • UI/CLI parity
  • Testmode for integration validation

What to adapt

  • Tool names: Claude's Bash(...) → my bash tool
  • Agent spawning: Claude's Agent{} → my task tool for subagents
  • Permissions: .claude/settings.json allow/deny → my system prompt + your instructions

When in doubt

Ask: "What would Claude do?" Then do that. The AGENTS.md is the bridge, not a replacement.


Quick Reference Card

Task Command
Discover clide commands clide capabilities
See current UI state clide status
Open ticket in UI clide ui open tickets T-NNN
Toast notification clide ui toast "msg" --severity info
List actionable tickets pql ticket list --under <id> --leaf --unblocked --status backlog --pretty
Sync decisions pql decisions sync
Run integration tests make run-testmode
Fast test suite make test
Full pre-push make push-check
Commit with message git commit -m "$(cat <<'EOF'\n<message>\nEOF\n)"
Verify changelog make changelog-gate

Generated for Mistral Vibe. Preserves Claude Code punch for clide repo.