carry forward ADRs, Claude Code config, and changelog discipline

Ports the patterns that crystallized during the short-lived claudian
plugin project (discarded in favour of this Flutter rebuild):

- ADRs 0001-0004 capture decisions that survive the host change —
  CLI-first over MCP, Go for the sidecar, pql as a supporter tool
  that becomes a clide-managed subsystem when present, and the
  ignore-file strategy that wires all file-enumerating surfaces
  through one knob in .pql/config.yaml.
- .claude/settings.json and the git-commit and skill-create skills
  come over with naming updated for clide. The git-commit skill's
  "no Conventional Commits" convention supersedes the Python-era
  clide style under legacy/; the Keep-a-Changelog discipline and
  the project.yaml-version-and-changelog-bumped-together rule
  apply going forward.
- CHANGELOG.md starts fresh at the repo root to track the Flutter
  rebuild. The Python changelog is preserved under legacy/.

.gitignore narrows from `.claude/` to just `.claude/settings.local.json`
so project-level config and skills travel with the repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 20:38:49 +02:00
co-authored by Claude Opus 4.7
parent a355751437
commit a782511470
9 changed files with 600 additions and 2 deletions
+37
View File
@@ -0,0 +1,37 @@
{
"permissions": {
"allow": [
"Bash(git add *)",
"Bash(git commit *)",
"Bash(go *)",
"Bash(make *)",
"Bash(golangci-lint *)",
"Bash(goreleaser *)",
"Bash(govulncheck *)",
"Bash(npm *)"
],
"deny": [
"Bash(rm -rf /*)",
"Bash(rm -rf ~*)",
"Bash(rm -rf $HOME*)",
"Bash(sudo rm *)",
"Bash(sudo chmod *)",
"Bash(sudo chown *)",
"Bash(mkfs*)",
"Bash(mkfs.*)",
"Bash(dd if=*)",
"Bash(git push --force*)",
"Bash(git push -f*)",
"Bash(git push --force-with-lease*)",
"Bash(git reset --hard*)",
"Bash(git clean -fd*)",
"Bash(git clean -fdx*)",
"Bash(git clean -ffd*)",
"Bash(git branch -D *)",
"Bash(git checkout -- *)",
"Bash(git restore .*)",
"Bash(chmod -R 777 *)",
"Bash(chmod 777 *)"
]
}
}
+113
View File
@@ -0,0 +1,113 @@
---
name: git-commit
description: >
Git commit conventions for this repo — message style, changelog and
version-bump rules, attribution trailer, and the safety rules that
always apply. Use whenever the user says "commit", "commit this",
"create a commit", "make a commit", "amend", or asks Claude to check
work into git in any form.
---
# Git commit rule — this repo
Follow these conventions whenever you create a commit in this repository. These are in addition to the standard Claude Code git-safety protocol (no `--no-verify`, no force-push to main, prefer new commits over `--amend`, etc.).
## Message style
- **First line:** imperative mood, ≤ 70 characters. Examples: `add sidecar PTY scaffold`, `fix IPC reconnect after app reload`, `update CLI exit-code contract`.
- **Body (optional):** wrap at ~72 chars. Explain the *why* — the reason this change exists. The diff already shows the *what*; don't restate it in prose.
- **No emojis.** Anywhere.
- **Don't prefix with types** like `feat:` or `fix:` — this repo isn't Conventional Commits. (The Python-era clide under `legacy/` used Conventional Commits; the Flutter rebuild at the repo root does not.)
- **Don't reference the current task or flow** (`for the v2.0 milestone`, `used by the canvas panel`) — that context belongs in the PR description and rots as the repo evolves.
- **Naming:** the project is `clide`. The Flutter desktop app lives at the repo root; the Go sidecar/CLI binary is `clide`. The supporter project is `pql` (referenced, not part of this repo). The archived Python implementation lives under `legacy/`.
## Logically-separated commits
Default to **one logical change per commit**, even when a lot of work lands in the tree at once. When there's a pile of uncommitted or untracked files:
1. **Read `git status` + `git diff` first** — never stage the whole tree blind.
2. **Group by concern**, not by file location. Typical concerns to separate:
- **Bookkeeping** — `.gitignore`, editor/IDE config, lockfiles, `go.sum` / `pubspec.lock` updates.
- **Documentation** — `README.md`, `CLAUDE.md`, ADRs under `docs/ADRs/`, design notes under `docs/`.
- **General-purpose tooling / skills** — things that aren't project-specific (reusable skills, shared scripts).
- **Project-specific conventions** — this repo's own rules.
- **Feature or subsystem** — one cohesive change per commit; a sidecar change and an app change for the same feature can land together, but two unrelated features should split.
- **Layer changes** — Flutter app, sidecar CLI, sidecar daemon, IPC server, pql wrapper, canvas driver, git panel — separate concerns; prefer separate commits when the changes are independent.
3. **Sequence the commits** so each one is cleanly scoped, but don't obsess about whether each intermediate commit "works" — for scaffolding PRs it's fine if the full picture only snaps together at the end.
4. **Prefer many small focused commits over one large mixed one** — a reviewer can read, revert, or cherry-pick a focused commit; they can't do any of those to a blob.
5. **Use `git add <specific paths>`** — never `git add -A` or `git add .` when splitting, or you'll sweep in the next commit's work by accident.
6. **Verify between commits** with `git status` and `git log -1` to confirm the split landed as intended.
Corollary: if a commit's subject line needs the word "and" to be accurate, it probably should have been two commits.
## Changelog discipline
This repo follows [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). **Every user-visible commit must touch `CHANGELOG.md`** under the `## [Unreleased]` section, in the appropriate subsection:
- **Added** — new features or capabilities.
- **Changed** — changes to existing functionality.
- **Deprecated** — soon-to-be-removed features.
- **Removed** — now-removed features.
- **Fixed** — bug fixes.
- **Security** — vulnerability fixes.
Entries should be short imperative phrases that describe user-facing impact — not implementation detail. "Added sidecar PTY support for terminal pane" beats "Added `internal/pty/session.go`."
**What skips the changelog:** pure bookkeeping commits that have no user-visible effect (typo fix in internal comment, `.gitignore` tweak, lint config change, reformatting). When in doubt, add an entry — the harm of an extra line is zero.
When a commit spans multiple entries (e.g. a feature that adds one thing and fixes another), add a line under each applicable subsection rather than cramming both into one.
## Cutting a release
Cutting a release is its own commit. In a single commit:
1. Move all entries from `## [Unreleased]` under a new heading `## [X.Y.Z] — YYYY-MM-DD`.
2. Leave an empty `## [Unreleased]` section at the top with its subsection skeleton ready.
3. Bump `project.yaml` `version:` to `X.Y.Z` (drop the `-dev` suffix for the tag; re-add it on the next development commit if desired).
4. Commit subject: `release vX.Y.Z`.
`project.yaml` is the single source of truth for the version — the Makefile reads it for ldflag stamping of the sidecar binary, and the Flutter app reads it for build info. Bumping `project.yaml` and the changelog out of sync is the mistake this rule prevents.
## Attribution trailer
Every commit ends with the Claude co-author line:
```
Co-Authored-By: Claude <noreply@anthropic.com>
```
The model-identifier variant produced by the Claude Code harness (e.g. `Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>`) is also accepted — don't rewrite it if the harness emits that form.
## HEREDOC discipline
Pass commit messages via HEREDOC so multi-line formatting survives:
```bash
git commit -m "$(cat <<'EOF'
short imperative summary
Optional longer body explaining why this change was needed,
wrapped at about 72 characters.
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"
```
Never pass multi-line messages via `-m "line1\nline2"` or multiple `-m` flags — Git's behavior differs between shells and quoting regimes and the trailer can end up in the wrong place.
## What not to commit
- `.env` and any `*.env.local` — see `.gitignore`.
- `.claude/settings.local.json` — user-specific Claude Code settings, ignored.
- Build artefacts: `sidecar/bin/`, `sidecar/dist/`, `build/` (Flutter output), `app/.dart_tool/` — gitignored.
- SQLite index files (`*.sqlite`, `*.sqlite-wal`, `*.sqlite-shm`, `*.db`) — caches generated against local repos; must never land here. Gitignored defensively.
- Coverage / test output (`*.out`, `coverage.*`, `*.test`) — gitignored.
## Safety reminders (reinforced from the global Claude Code protocol)
- **Never** `--no-verify`. If a pre-commit hook fails, fix the underlying issue and create a new commit.
- **Never** `--amend` a commit unless the user explicitly asks. A failed-hook commit didn't land, so amending would overwrite the *previous* commit and lose work.
- **Never** force-push to `main` or `master`. Warn the user if they ask.
- When staging, prefer naming specific files over `git add -A` / `git add .` — those can sweep in secrets or unintended files.
- `git status` before staging, `git diff --staged` before committing, `git log -1` after committing to confirm.
+203
View File
@@ -0,0 +1,203 @@
---
name: skill-create
description: >
Guidance for creating effective Claude Code skills (.skill packages).
Use when the user wants to create, build, design, or iterate on a skill —
including writing SKILL.md files, bundling scripts/references/assets,
initializing new skills, packaging skills, or improving existing ones.
Triggers on requests like "create a skill", "make a new skill",
"build a skill for X", "package this skill", or "improve my skill".
---
# Skill Creator
## About Skills
Skills are modular, self-contained packages that extend Claude's capabilities
by providing specialized knowledge, workflows, and tools. They transform Claude
from a general-purpose agent into a specialized agent equipped with procedural
knowledge that no model can fully possess.
### What Skills Provide
- **Specialized workflows** — Multi-step procedures for specific domains
- **Tool integrations** — Instructions for working with specific file formats or APIs
- **Domain expertise** — Company-specific knowledge, schemas, business logic
- **Bundled resources** — Scripts, references, and assets for complex and repetitive tasks
## Core Principles
### Concise is Key
The context window is a public good. Skills share it with everything else Claude
needs: system prompt, conversation history, other skills' metadata, and the
actual user request.
Default assumption: Claude is already very smart. Only add context Claude doesn't
already have. Challenge each piece of information: "Does Claude really need this
explanation?" and "Does this paragraph justify its token cost?"
Prefer concise examples over verbose explanations.
### Set Appropriate Degrees of Freedom
Match specificity to the task's fragility and variability:
- **High freedom** (text-based instructions): Multiple approaches valid, decisions
depend on context, heuristics guide the approach.
- **Medium freedom** (pseudocode or scripts with parameters): Preferred pattern
exists, some variation acceptable, configuration affects behavior.
- **Low freedom** (specific scripts, few parameters): Operations are fragile and
error-prone, consistency is critical, specific sequence must be followed.
Think of Claude as exploring a path: a narrow bridge with cliffs needs specific
guardrails (low freedom), while an open field allows many routes (high freedom).
## Anatomy of a Skill
```
skill-name/
├── SKILL.md (required)
│ ├── YAML frontmatter metadata (required)
│ │ ├── name: (required)
│ │ ├── description: (required)
│ │ └── compatibility: (optional, rarely needed)
│ └── Markdown instructions (required)
└── Bundled Resources (optional)
├── scripts/ - Executable code (Python/Bash/etc.)
├── references/ - Documentation loaded into context as needed
└── assets/ - Files used in output (templates, icons, fonts, etc.)
```
### SKILL.md (required)
- **Frontmatter (YAML)**: `name` and `description` fields (required). Only these
are read by Claude to determine when the skill triggers — be clear and
comprehensive. The `compatibility` field is for environment requirements but
most skills don't need it.
- **Body (Markdown)**: Instructions and guidance. Only loaded AFTER the skill
triggers.
### Bundled Resources (optional)
**Scripts (`scripts/`)** — Executable code for tasks requiring deterministic
reliability or that are repeatedly rewritten.
**References (`references/`)** — Documentation loaded as needed into context.
Keep SKILL.md lean; move detailed reference material, schemas, and examples here.
If files are large (>10k words), include grep search patterns in SKILL.md.
**Assets (`assets/`)** — Files used in output, not loaded into context (templates,
images, icons, boilerplate code, fonts).
### What to NOT Include
Do NOT create extraneous files like README.md, INSTALLATION_GUIDE.md,
QUICK_REFERENCE.md, CHANGELOG.md, etc. The skill should only contain information
needed for an AI agent to do the job.
## Progressive Disclosure
Skills use a three-level loading system:
1. **Metadata** (name + description) — Always in context (~100 words)
2. **SKILL.md body** — When skill triggers (<5k words)
3. **Bundled resources** — As needed (unlimited; scripts can run without reading)
Keep SKILL.md body under 500 lines. Split content into separate files when
approaching this limit. Reference split files from SKILL.md with clear
descriptions of when to read them.
### Disclosure Patterns
**Pattern 1: High-level guide with references** — Keep overview in SKILL.md,
link to detail files loaded only when needed.
**Pattern 2: Domain-specific organization** — Organize content by domain
(e.g., `references/finance.md`, `references/sales.md`) so only relevant content
is loaded.
**Pattern 3: Conditional details** — Show basic content, link to advanced
content loaded only when the user needs those features.
Guidelines:
- Avoid deeply nested references — keep one level deep from SKILL.md
- Structure longer reference files with a table of contents at the top
## Skill Creation Process
Follow these steps in order, skipping only with clear reason:
### Step 1: Understand the Skill with Concrete Examples
Skip only when usage patterns are already clearly understood.
Ask the user for concrete examples of how the skill will be used:
- "What functionality should the skill support?"
- "Can you give some examples of how this skill would be used?"
- "What would a user say that should trigger this skill?"
Avoid overwhelming users — start with the most important questions.
### Step 2: Plan the Reusable Skill Contents
Analyze each example by considering how to execute from scratch and identifying
what scripts, references, and assets would help with repeated execution.
Establish a list of reusable resources: scripts, references, and assets.
### Step 3: Initialize the Skill
Create the skill directory manually:
```
mkdir -p <output-directory>/<skill-name>
```
Then create `SKILL.md` with frontmatter and body. Add `scripts/`, `references/`,
and `assets/` subdirectories only as needed.
Skip if iterating on an existing skill.
### Step 4: Edit the Skill
Remember the skill is for another Claude instance to use. Include beneficial,
non-obvious information.
For design patterns, consult:
- `references/workflows.md` — Sequential workflows and conditional logic
- `references/output-patterns.md` — Template and example patterns
**Implementation order:**
1. Start with reusable resources (`scripts/`, `references/`, `assets/`)
2. Test added scripts by running them
3. Delete unused example files from initialization
4. Update SKILL.md
**Writing guidelines:** Always use imperative/infinitive form.
**Frontmatter:**
- `name`: The skill name — use **domain-action** naming: `{domain}-{action}`.
The domain is the system/area the skill operates on, the action is what it does.
Examples: `pr-review`, `sprint-plan`, `docs-search`, `git-commit`, `debt-scan`.
Multi-action wrappers (like `ticket`) can use the domain name alone.
The directory name must match the `name` field.
- `description`: Primary triggering mechanism. Include what the skill does AND
specific triggers/contexts. All "when to use" info goes here (not in body).
**Body:** Instructions for using the skill and its bundled resources.
### Step 5: Validate the Skill
Check the skill manually:
- Frontmatter has `name` and `description`
- SKILL.md body is under 500 lines
- No extraneous files (README.md, CHANGELOG.md, etc.)
- Scripts are executable and tested
- References are referenced from SKILL.md
### Step 6: Iterate
After real usage, notice struggles or inefficiencies, identify needed updates,
implement changes, and test again.
+2 -2
View File
@@ -184,5 +184,5 @@ logs/
# Credentials
*-credentials.md
# Claude Code
.claude/
# Claude Code — user-specific settings only; project-level settings and skills are committed
.claude/settings.local.json
+33
View File
@@ -0,0 +1,33 @@
# Changelog
All notable changes to clide are documented in this file.
The format follows [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
This changelog tracks the Flutter rebuild at the repo root. The Python
Textual implementation's changelog is preserved under
[`legacy/CHANGELOG.md`](legacy/CHANGELOG.md).
Versions are tracked in [`project.yaml`](project.yaml) under `version:`,
which is the single source of truth. Cutting a release means (a) moving
the entries below from `## [Unreleased]` under a new dated version
heading, and (b) bumping `project.yaml` `version:` in the same commit.
## [Unreleased]
### Added
- Architectural decision records carried forward from the short-lived
`claudian` plugin project (discarded in favour of this Flutter
rebuild):
[ADR 0001](docs/ADRs/0001-cli-first-not-mcp.md) — CLI-first, not MCP.
[ADR 0002](docs/ADRs/0002-sidecar-language-go.md) — Sidecar language: Go.
[ADR 0003](docs/ADRs/0003-pql-as-supporter-tool.md) — pql as supporter tool; wrap, don't duplicate; pql is a Clide subsystem when present.
[ADR 0004](docs/ADRs/0004-ignore-file-strategy.md) — Ignore file strategy (`ignore_files:` in `.pql/config.yaml`, layered).
- Claude Code configuration under `.claude/`: project-level
allow/deny permissions and two skills — `skill-create` (generic
skill authoring guidance) and `git-commit` (this repo's commit
conventions: no Conventional Commits, Keep a Changelog discipline,
`project.yaml`-and-changelog-bumped-together rule, attribution
trailer, safety reminders).
+34
View File
@@ -0,0 +1,34 @@
# ADR 0001 — CLI-first, not MCP
**Status:** accepted
**Date:** 2026-04-20 (ported from the claudian lineage)
## Context
Clide exposes capabilities to Claude Code (panes, terminals, git,
pql queries, canvas, graph). The two mainstream options for that
interface are:
1. A Model Context Protocol (MCP) server the agent connects to.
2. A plain Bash CLI the agent calls from its shell, matching the
contract `pql` already follows.
## Decision
Claude talks to Clide exclusively via Bash (`clide ...`). No MCP
server. No protocol layer in Claude's face. The CLI uses the same
exit-code + stderr-JSON contract as pql.
## Consequences
- Same mental model as pql for the agent — one tool-use pattern
covers both.
- No MCP runtime to host, authenticate, or keep in sync with client
versions.
- User/Claude parity is easier to enforce: every CLI subcommand must
have a UI affordance in the Flutter app and vice versa.
- Claude Code's `Bash(clide *)` allow rule is the only configuration
Clide needs on the agent side.
- If an MCP-only integration becomes compelling later (e.g. a
multi-agent scenario), nothing here precludes adding one that
shells out to the same CLI.
+44
View File
@@ -0,0 +1,44 @@
# ADR 0002 — Sidecar language: Go
**Status:** accepted
**Date:** 2026-04-20 (ported from the claudian lineage)
## Context
The Clide sidecar owns PTYs, subprocesses, file watchers, git
shelling-out, and the IPC server. It ships as a single static binary
that also serves as the `clide` CLI in one-shot mode. The Flutter
desktop app talks to it over IPC; Claude talks to it via the CLI.
Language candidates were Go and Rust.
Related hard constraint: **no heavy lifting in the UI layer.** The
Flutter app stays focused on rendering and interaction. Everything
heavy (PTYs, subprocesses, file watching, git, pql invocations)
lives in the sidecar. Reason: keep the UI layer thin and the
security-sensitive surface auditable in one language.
## Decision
The sidecar/CLI is written in Go.
Rationale:
- **Matches pql.** pql is Go; Clide wraps pql and reaches into its
idioms constantly. Shared toolchain and shared patterns cut
cognitive overhead.
- **Static binary.** Single artifact, trivial cross-compile, no
runtime dependencies on the user's machine.
- **PTY story is fine.** `creack/pty` covers what we need; Rust's
crates are marginally nicer but not decisive.
- **Muscle memory.** Build pipeline, `project.yaml` conventions,
goreleaser setup, exit-code contract, diagnostic format — all
already established in pql and portable one-to-one.
## Consequences
- Module path: `git.schweitz.net/jpmschweitzer/clide/sidecar`.
- Layout mirrors pql: `cmd/clide/main.go`, `internal/cli`,
`internal/version` (ldflag-stamped `Version`, `Commit`, `Date`),
`internal/diag` (exit codes + stderr-JSON diagnostics).
- Same Makefile shape: version read from `project.yaml` via awk,
stamped via `-ldflags -X`.
+61
View File
@@ -0,0 +1,61 @@
# ADR 0003 — pql as supporter tool; Clide wraps, never duplicates
**Status:** accepted
**Date:** 2026-04-20 (ported from the claudian lineage)
## Context
[`pql`](https://github.com/postmeridiem/pql) is a pre-existing Go
CLI that indexes a markdown-bearing directory tree into SQLite and
exposes its semantics (frontmatter, wikilinks, tags, headings,
bases) through a query surface. Clide needs those capabilities for
its Query panel, canvas drivers, graph view, and any feature that
needs to know structure.
## Decision
Two complementary rules.
### 1. Wrap, don't duplicate.
Clide never re-implements backlinks, ranking, frontmatter parsing,
or wikilink resolution for query purposes. If a capability is
missing in pql, it is added upstream in pql's repo and Clide bumps
the dependency.
The only place Clide contains pql logic is
`sidecar/internal/pql/` — pure shell-outs to the `pql` binary, no
logic beyond invocation and result rendering.
### 2. pql is a Clide subsystem when Clide is present in the repo.
Broader than "wrap, don't duplicate." When Clide is loaded in a
repo, it owns pql's lifecycle and the config keys it cares about.
On load, Clide writes its current state into `.pql/config.yaml`
no conditional sync, no "did anything change" logic.
Clide only stomps the keys it manages (starting with `ignore_files:`
— see ADR 0004). Other pql config keys are left alone so pql's
config surface can grow independently.
Clide does **not** touch pql's index/cache data under `<repo>/.pql/`
— that stays pql's private store. Only the config file is Clide's
to edit.
In repos without Clide, pql works standalone, unaffected. The rule:
direct-pql users get vanilla pql; Clide users get pql managed by
Clide.
## Consequences
- One source of truth for markdown semantics (pql).
- Clide's `sidecar/internal/pql/` package is deliberately thin.
- Any new query capability the UI wants goes through a pql upstream
PR, not a local workaround.
- User never has to learn pql's config file to get consistent
behavior — Clide manages it.
- The arrow Clide → pql is never inverted: pql stays ignorant of
its wrapper, never hardcodes Clide filenames.
- pql is also the **only** query engine. Obsidian-style inline
"bases" (YAML query tables embedded in markdown) are explicitly
not supported; queries live at the repo level where they belong.
+73
View File
@@ -0,0 +1,73 @@
# ADR 0004 — Ignore file strategy
**Status:** accepted
**Date:** 2026-04-20 (ported from the claudian lineage)
## Context
Clide's working assumption is that the git repo *is* the workspace
— no separate "vault" concept layered on top. Every file-enumerating
surface in Clide (pql query panels, canvas drivers, graph view,
sidecar file watchers, pane lists, file tree) needs to skip the
obvious junk — `vendor/`, `node_modules/`, `dist/`, build artifacts
— or results drown in noise.
## Decision
One mechanism everywhere: the `ignore_files:` list in
`.pql/config.yaml`. An ordered list of gitignore-shaped files, later
entries win on per-pattern conflicts.
### Default
pql defaults to `ignore_files: [.gitignore]`. Most repos already
keep exclusions there, so zero config in a code repo; in a
notes-only directory `.gitignore` doesn't exist and the default is
a safe no-op.
### Clide sync
Per ADR 0003's "pql is a Clide subsystem when present" rule, Clide
writes the list on load:
- If `.clideignore` exists in the repo:
`ignore_files: [.gitignore, .clideignore]`. Clide-specific deltas
(including `!pattern` negations) layer on top of gitignore.
- Otherwise: `ignore_files: [.gitignore]` (matches the pql default).
No conditional sync. Clide only stomps `ignore_files:`; other pql
config keys are left alone.
### `.clideignore` semantics
- Carries **only** the Clide-specific deviations from `.gitignore`.
Never duplicate gitignore's contents.
- Supports `!pattern` negations to un-ignore specific entries (e.g.
`!.github/` to expose workflow docs in query results).
### Walker magic: none except `.git/`
Git self-hides `.git/` — that's the only invisible exclusion in the
stack. Every other tool is explicit: pql adds `.pql/` to
`.gitignore` at install time, and Clide adds any private dirs it
introduces (e.g. `.clide/`) to `.gitignore` on install. Exclusion
flows through the normal `ignore_files:` chain; no hardcoded walker
exceptions for tool-owned dirs.
### Same list, same rules, everywhere
Sidecar consumers (watchers, canvas, pane list, file tree, graph
view) read the same key from `.pql/config.yaml` and apply identical
precedence, so Claude and the user always see the same filtered
surface.
## Consequences
- Users get one config knob, in a file they might already know (pql
users) or never need to touch (Clide-only users).
- `.clideignore` is short by design — it's deltas, not a full list.
- Removing Clide from a repo leaves pql working with vanilla
defaults (Clide's last-written `ignore_files:` stays until pql or
the user rewrites it; worth reconsidering during uninstall design).
- Upstream pql work: the `ignore_files:` list is already the shape
pql has landed on (plural, ordered, defaults to `[.gitignore]`).