# 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 ` 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/.md` as `D-NNN` records. Open questions as `Q-NNN` under `governance/questions/.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 ``` (): () Optional body: explain WHY, not WHAT. Wrap at ~72 chars. Co-Authored-By: Mistral Vibe ``` **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 `** — 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: ```bash git commit -m "$(cat <<'EOF' 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 ```bash 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 ```bash 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 ` | Files linking TO a path | | `pql outlinks ` | Links FROM a file | | `pql meta ` | Frontmatter + tags + outlinks + headings for one file | | `pql schema` | Typed frontmatter schema | | `pql base ` | Execute an Obsidian .base file | | `pql shell` | Interactive REPL (indexes once, then query per line) | | `pql query ""` | SQL-derived DSL for complex queries | | `pql doctor` | Resolved vault/config/DB/index state | #### DSL examples ```sql 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 folder** → `pql files 'sessions/*'` - **Top tags** → `pql tags --sort count --limit 20` - **What links to X?** → `pql backlinks members/vaasa/persona.md` - **Date range** → `pql query "SELECT name, fm.date WHERE fm.date BETWEEN '2024-01-01' AND '2024-12-31'"` - **Run a Base** → `pql base council-sessions` - **Inspect one file** → `pql meta members/vaasa/persona.md --pretty` --- ### Surface 2: Planning (decisions + tickets) Planning state lives in `/.pql/pql.db` (user-authored state, not a cache). Decision records come from the DQR tree — `governance/{decisions, questions,rejected}/.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 "title"` | Print next available ID | | `pql decisions list [--type X] [--domain X] [--status X]` | List decisions | | `pql decisions show [--with-refs] [--with-tickets]` | Show with joins | | `pql decisions coverage` | Confirmed decisions without tickets | | `pql decisions refs ` | Cross-references involving a decision | Always `pql decisions sync` before querying if decisions/*.md may have changed. #### Ticket subcommands | Command | Purpose | |---|---| | `pql ticket new "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 [--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 [--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 [--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 ` | Set assignee | | `pql ticket setparent ` | 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 ` | Append to the description (blank-line separated); never round-trips existing text | | `pql ticket block --by ` | 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 --from ` | Remove blocker | | `pql ticket team ` | Set team | | `pql ticket label add\|rm