add audit, dogfood, and pql-improvement notes under docs/
Three analysis docs that were loose at the repo root: the 2026-05-26 codebase cleanliness audit, the dogfood self-analysis of whether Claude can work inside clide, and the pql improvement notes for upstream. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f90bcbf5f3
commit
fa1e71d175
+105
@@ -0,0 +1,105 @@
|
||||
# Codebase Cleanliness & Pattern Audit
|
||||
|
||||
**Date:** 2026-05-26
|
||||
**Scope:** `lib/` (314 files, ~2.1MB) and `pubspec.yaml`. Skipped `legacy/`, `tests/`, generated files. Conventions grounded in [`CLAUDE.md`](CLAUDE.md) guardrails and the [`governance/decisions/`](governance/decisions/) D-records (architecture, extensions, testing, tooling, process).
|
||||
|
||||
## Baseline health
|
||||
|
||||
- `dart format --set-exit-if-changed`: **468/468 files clean.**
|
||||
- `flutter analyze`: **3 warnings, all in a single WIP file** (`lib/builtin/claude/src/session_orchestrator.dart`), already in the modified-but-uncommitted set:
|
||||
- L15: unused `dart:convert` import
|
||||
- L16: unused `dart:io` import
|
||||
- L29: unused private field `_resumeTailBytes`
|
||||
- No `print(` / `debugPrint(` in `lib/`. No TODO / FIXME / HACK comments. No commented-out code blocks. No orphaned `.dart` files.
|
||||
|
||||
The repo is in unusually good baseline hygiene shape — the audit's interesting findings are structural, not janitorial.
|
||||
|
||||
## Guardrail / D-record compliance
|
||||
|
||||
| Decision | Status | Notes |
|
||||
|---|---|---|
|
||||
| **D-7** bare `WidgetsApp` | Pass | No `MaterialApp`/`CupertinoApp`/`Scaffold`/`ElevatedButton`. Material/Cupertino imports exist only in inlined xterm heritage under `lib/src/terminal/` and aren't instantiated. |
|
||||
| **D-8** feature-first, barrels only | Pass | No cross-feature reach into another feature's `src/`. `lib/extension/src/` → `lib/kernel/src/` is the one cross-`src/` link (extension framework on platform foundation — legitimate). |
|
||||
| **D-10** ChangeNotifier + ListenableBuilder | Pass | No provider/riverpod/bloc/get_it. Three `InheritedWidget` subclasses (`ScrollbarTheme`, `ClideKernel`, `ClideTheme` via `InheritedNotifier<ThemeController>`) are all justified scoped-context uses. |
|
||||
| **D-31 / D-42** exact-pin + `licenses.yaml` | Pass | No caret ranges in `pubspec.yaml`. All 13 runtime deps + dev deps + native binaries documented. |
|
||||
| **D-46** core frame vs shipped extensions | **Drift** | `editor`, `claude`, `claude-control`, `markdown`, `diff`, `git-ui`, `pql`, `canvas`, `graph`, `decisions`, `tickets`, `todos`, `problems` should be shipped extensions on a separate registration path. They still live in `lib/builtin/` alongside core frame builtins. Architectural intent documented but not enforced — migration deferred. |
|
||||
| **D-56** single package, in-process IPC | Pass | No `bin/clide.dart`, no `app/`, no `sidecar/`. `lib/src/daemon/` is in-process dispatcher + handlers. |
|
||||
| **D-1 / D-68** CLI primary, MCP secondary | Pass | `lib/src/ipc/server.dart` (unix socket) and `lib/src/ipc/mcp_server.dart` (HTTP+SSE) both wrap the same `DaemonDispatcher`. |
|
||||
| **D-72** serial dispatch on main isolate | Pass | `server.dart:212` awaits `dispatcher.dispatch(req)` inside a per-client serial line handler. |
|
||||
| **D-74** schema co-registered | Pass | `DaemonDispatcher` accepts `CommandSchema?` at registration (`dispatcher.dart:23`), validates pre-handler (L55–59). |
|
||||
| **D-66** 95% coverage floor | Pass | `pubspec.yaml:26`: `coverage_floor: 95`. |
|
||||
| **D-75 / D-77 / D-78** Claude coupling isolation | Pass | All `~/.claude/`, transcript JSONL, `claude` CLI invocations live behind `lib/builtin/claude/src/`. No leakage to other features. |
|
||||
| **CLAUDE.md** in-house renderers | Pass | Markdown: pub.dev parser (per D-58) + custom renderer in `lib/widgets/src/clide_markdown.dart`. Canvas + graph in-house. |
|
||||
| **Analyzer suppressions** | Pass | `// ignore`s are confined to xterm heritage code, FFI bindings (C naming), and lookup tables. All justified. |
|
||||
|
||||
## Findings worth acting on
|
||||
|
||||
### 1. Unused pubspec dependencies (D-31 violation in spirit)
|
||||
|
||||
- `flutter_widget_from_html_core: 0.17.2` — listed in `dependencies:`, imported nowhere. Mentioned in D-58 as adoptable, but no current consumer.
|
||||
- `mocktail: 1.0.4` — listed in `dev_dependencies:`, imported nowhere. D-25 specifies it for IO mocks, but no tests use it today.
|
||||
|
||||
Per D-62 (Dependency removal process), removing requires the full 5-step PR. But carrying them violates D-31's "what stays is exact-pinned" intent — the spirit being "we keep only what we use."
|
||||
|
||||
### 2. D-46 architectural drift — known but uncodified
|
||||
|
||||
Thirteen "shipped extension" features still register through the core frame path. This is documented drift, not new — but it's the largest unresolved architectural debt. A dedicated `lib/extensions/` directory + a second registration tier is the prescribed fix.
|
||||
|
||||
### 3. Three hotspot files (>800 lines, mixed concerns)
|
||||
|
||||
| File | Lines | Shape |
|
||||
|---|---|---|
|
||||
| `lib/app.dart` | 1175 | 11+ State classes for sidebar/workspace/editor/context/status — split by region |
|
||||
| `lib/src/terminal/src/core/escape/parser.dart` | 1139 | `EscapeParser` FSM, 1095-line class — handler logic could split by escape domain |
|
||||
| `lib/src/terminal/src/terminal.dart` | 907 | `Terminal` class implementing 5 interfaces, 80+ methods spanning cursor/buffer/input/output |
|
||||
|
||||
The terminal pair is partially inlined heritage code (xterm.dart) so refactoring it competes with merge-friendliness; `app.dart` is yours to split freely.
|
||||
|
||||
### 4. Silent error swallowing in `lib/builtin/claude/src/claude_config.dart`
|
||||
|
||||
Seven `catch (_)` sites (L292, 301, 314, 394, 460, 489, 505) in config/skill loading. Config parsing failures vanish without log or UI signal. Per D-76 the service is supposed to "degrade gracefully" on parse miss — that's fine, but at minimum these should log to make schema drift visible (D-75 / D-78 explicitly call out that detection is the mitigation for CC-internals drift).
|
||||
|
||||
### 5. Long methods — theme resolvers and one claude config probe
|
||||
|
||||
| File:Line | Method | Lines |
|
||||
|---|---|---|
|
||||
| `lib/kernel/src/theme/resolver.dart:9` | `palette()` | 172 |
|
||||
| `lib/kernel/src/theme/resolver.dart:11` | `semantic()` | 170 |
|
||||
| `lib/kernel/src/theme/resolver.dart:13` | `surface()` | 168 |
|
||||
| `lib/builtin/claude/src/claude_config.dart:306` | `_parseInitProbe()` | 178 |
|
||||
|
||||
Theme resolvers are dense token tables (data-shaped, not control-flow) — borderline but tolerable. The probe parser is the strongest splitting candidate.
|
||||
|
||||
### 6. Suspicious duplication
|
||||
|
||||
- `lib/builtin/tickets/src/tickets_view.dart` + `ticket_detail_view.dart` — 4+ near-identical `builder: (ctx, hovered, _) => ...` responsive button scaffolds. Extract a factory widget.
|
||||
|
||||
### 7. Magic strings worth a constant
|
||||
|
||||
- `'type': 'request' | 'response' | 'event'` recurs across `lib/src/ipc/envelope.dart` (L42, 79, 141). With two transports (socket + MCP) both speaking JSON envelopes, these belong as enum-or-const so a typo can't silently land.
|
||||
- `lib/builtin/claude/src/transcript_reader.dart` (L477, 495, 498): `'user'`, `'assistant'`, `'permission-mode'` — strong candidates for an enum per the D-75 isolation principle (one place that knows the schema).
|
||||
|
||||
### 8. Coupling hub
|
||||
|
||||
`lib/main.dart` imports from 51 files — boot orchestrator, expected, but fragile. Splittable into `boot_kernel.dart` / `boot_ipc.dart` / `boot_ui.dart` if it grows further.
|
||||
|
||||
## What's notably *not* a problem
|
||||
|
||||
- No god-object utilities (`utils.dart`, `helpers.dart`, etc.) — feature-first discipline holds.
|
||||
- No unchecked `as` casts — every cast is guarded by `is` or null-coalesce.
|
||||
- No `dynamic` overuse outside legitimate JSON / Flutter API boundaries.
|
||||
- Naming is uniformly Dart-idiomatic across 314 files.
|
||||
- No deep control-flow nesting outside idiomatic `build()` trees.
|
||||
|
||||
## Recommended next moves
|
||||
|
||||
1. Land the three analyzer warnings in `session_orchestrator.dart` as part of the in-flight commit.
|
||||
2. Decide on `flutter_widget_from_html_core` and `mocktail` — either wire them in or remove them via the D-62 process.
|
||||
3. Open a tracking ticket for the D-46 migration if one doesn't exist; this is the only meaningful drift.
|
||||
4. Split `app.dart` by layout region — lowest-risk, highest-readability win.
|
||||
5. Add logging (not exception propagation) to the `claude_config.dart` silent catches so schema drift surfaces during real use.
|
||||
6. Extract envelope type strings to constants/enum in `lib/src/ipc/envelope.dart` before the second transport (MCP) accumulates more divergence.
|
||||
|
||||
## Overall assessment
|
||||
|
||||
This is a tidy codebase. The audit found one architectural drift (D-46, already documented), three localized hotspots, two stale pubspec entries, and a handful of cosmetic improvements. Nothing systemic.
|
||||
@@ -0,0 +1,164 @@
|
||||
# pql — improvement notes from a live session
|
||||
|
||||
Feedback for [`postmeridiem/pql`](https://github.com/postmeridiem/pql), gathered
|
||||
while using pql as the planning backend for the `clide` repo. Everything below
|
||||
was observed first-hand, not inferred from docs.
|
||||
|
||||
**Environment**
|
||||
|
||||
- pql `1.5.0`, commit `ab191fb`, schema_version 1 (binary), DB schema_version 2.
|
||||
- Consumer: a single-dev repo using pql for decisions + tickets, with pql's
|
||||
installed git hooks (`.pql/hooks/post-checkout`, `post-merge`, `post-rewrite`,
|
||||
`pre-commit`) and a git-tracked `.pql/changelog/` + `.pql/pql-plan.json`.
|
||||
|
||||
The core is genuinely good — structural queries, the decision/ticket model, exit
|
||||
codes, and the changelog-as-source-of-truth idea all worked. The notes below are
|
||||
where it bit us or surprised us, roughly in priority order.
|
||||
|
||||
---
|
||||
|
||||
## 1. CRITICAL — ticket mutations aren't persisted, and rebuild-on-checkout silently destroys them
|
||||
|
||||
**Observed.** `pql ticket new` (and `ticket status` / `ticket block`) write only to
|
||||
`.pql/pql.db`, which is gitignored. Nothing writes through to the git-tracked
|
||||
`.pql/changelog/` automatically. Separately, pql's installed `post-checkout` and
|
||||
`post-merge` hooks run `pql plan rebuild`, which replays the **committed**
|
||||
changelog and overwrites `pql.db`.
|
||||
|
||||
The two facts combine into silent data loss:
|
||||
|
||||
1. Created an 18-ticket tree (an initiative + 4 epics + tasks, with blockers and
|
||||
decision refs) via a series of `pql ticket new` calls. Verified present in
|
||||
`pql ticket list`.
|
||||
2. A routine `git checkout` fired `post-checkout` → `pql plan rebuild` → `pql.db`
|
||||
was rebuilt from the changelog, which still ended at the previous max ticket.
|
||||
3. All 18 tickets were gone. No warning, no prompt.
|
||||
|
||||
**Impact.** Total, silent loss of un-exported planning work on an ordinary git
|
||||
operation. The user did nothing wrong — they switched branches.
|
||||
|
||||
**Repro.**
|
||||
```bash
|
||||
pql ticket new task "scratch ticket" # lands in pql.db only
|
||||
git checkout -b somebranch # post-checkout runs `pql plan rebuild`
|
||||
pql ticket list | grep "scratch" # gone
|
||||
```
|
||||
|
||||
**Suggested fixes** (any one closes the hole; (a) is the principled one):
|
||||
|
||||
- **(a) Write-through.** Have ticket/decision mutations append to the changelog
|
||||
at mutation time, making the changelog the log of record and `pql.db` a derived
|
||||
cache. Then rebuild is always safe.
|
||||
- **(b) Divergence guard.** `pql plan rebuild` (and the hooks that call it) should
|
||||
detect when `pql.db` holds rows not represented in the changelog and refuse or
|
||||
loudly warn instead of overwriting — e.g. *"pql.db has 18 un-exported rows; run
|
||||
`pql plan export` first, or pass --force."*
|
||||
- **(c) Non-destructive rebuild.** Merge the changelog into `pql.db` rather than
|
||||
replacing it.
|
||||
|
||||
At an absolute minimum, the `post-checkout`/`post-merge` hooks should not
|
||||
discard local state without a word.
|
||||
|
||||
---
|
||||
|
||||
## 2. `pql plan export` writes the changelog, but docs/help say it writes a JSON snapshot
|
||||
|
||||
**Observed.** `pql plan export` wrote:
|
||||
```
|
||||
{"files_written":[".pql/changelog/ticket_deps/2026-06.sql",
|
||||
".pql/changelog/tickets/2026-06.sql"],"rows_written":23}
|
||||
```
|
||||
It did **not** touch `.pql/pql-plan.json`, which stayed frozen at an older date
|
||||
across every mutation and export this session. But the `--help` text and the
|
||||
bundled skill both describe export as *"Snapshot planning state to JSON (default:
|
||||
`pql-plan.json`)"* and recommend committing `pql-plan.json`.
|
||||
|
||||
**Impact.** Users (and the bundled skill) commit `pql-plan.json` believing it is
|
||||
the durable artifact. It is stale. The actually-durable artifact is the
|
||||
changelog. This directly compounds #1 — people think they've versioned their
|
||||
planning state when they haven't.
|
||||
|
||||
**Suggested fix.** Make `--help`, docs, and the embedded skill match real
|
||||
behavior. Clarify the role of `pql-plan.json` vs `.pql/changelog/`: is the JSON
|
||||
snapshot deprecated in favor of the changelog? If both exist, document which one
|
||||
`pql plan import` / `pql plan rebuild` prefer.
|
||||
|
||||
---
|
||||
|
||||
## 3. Schema upgrade is a hard break requiring multi-step manual recovery
|
||||
|
||||
**Observed.** After a pql binary upgrade, every planning command failed:
|
||||
```
|
||||
$ pql decisions sync
|
||||
planning: decision_refs.created_at missing — pql.db is from an earlier schema.
|
||||
$ pql plan status
|
||||
planning: decisions.created_at missing — pql.db is from an earlier schema.
|
||||
```
|
||||
(exit 69). Recovery was manual and multi-step: delete `pql.db`, `pql plan
|
||||
rebuild`, then `pql decisions sync`.
|
||||
|
||||
**Impact.** All planning surfaces are dead until the user performs a manual
|
||||
recovery they have to read out of the error text. Easy to get wrong (the error
|
||||
also offers a `--legacy pql-plan.json` path — see #4).
|
||||
|
||||
**Suggested fix.** Auto-migrate the schema on open (additive column adds are
|
||||
cheap), or ship a single `pql plan repair` / `pql migrate` command that performs
|
||||
the safe delete-rebuild-sync sequence (with a backup of the old DB).
|
||||
|
||||
---
|
||||
|
||||
## 4. Schema-error recovery hint can point at the stale snapshot
|
||||
|
||||
**Observed.** The schema error (see #3) lists recovery options including
|
||||
`pql plan import --legacy .pql/pql-plan.json`. Given #2 (that file is stale), a
|
||||
user following that branch restores an out-of-date snapshot. The correct path
|
||||
was the changelog rebuild.
|
||||
|
||||
**Suggested fix.** In the recovery list, prefer/recommend `pql plan rebuild` when
|
||||
`.pql/changelog/` is present, and annotate the `pql-plan.json` option as
|
||||
potentially stale.
|
||||
|
||||
---
|
||||
|
||||
## 5. Scripting ergonomics — no id-only output from `pql ticket new`
|
||||
|
||||
**Observed.** Building a ticket tree means capturing each created ticket's id to
|
||||
use as the next call's `--parent`/blocker. `pql ticket new` emits the full ticket
|
||||
JSON, so a creation script must parse `.id` out of every call.
|
||||
|
||||
**Suggested fix.** A `--quiet` / `--id-only` (or `-o id`) flag that prints just
|
||||
the new `T-NNN`, so tree-creation scripts stay simple. (Determinism is already a
|
||||
strength: re-running the same `new` calls in order against a clean baseline
|
||||
reproduces the same ids — which is what let us recover from #1.)
|
||||
|
||||
---
|
||||
|
||||
## 6. Minor — bundled skill assumes binary features the installed version lacks
|
||||
|
||||
**Observed.** The bundled `pql` skill documents `pql ticket show --tree`,
|
||||
`--leaf`, `--unblocked`, `--under`, and `pql ticket append` (annotated "pql ≥
|
||||
1.6.0"). The installed binary reports 1.5.0 as current (`pql doctor` /
|
||||
`pql skill status`), and rejects them:
|
||||
```
|
||||
$ pql ticket show T-65 --tree
|
||||
unknown flag: --tree # exit 64
|
||||
```
|
||||
|
||||
**Impact.** A consumer following the skill hits unknown-flag errors and has to
|
||||
discover the 1.5.0 fallbacks (`--with-children`, `--with-blockers`) by trial.
|
||||
|
||||
**Suggested fix.** Keep the embedded skill's documented surface in lockstep with
|
||||
the binary it ships alongside, or have `pql skill install` stamp/gate
|
||||
version-specific sections so the skill never advertises flags the paired binary
|
||||
doesn't have.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The one that matters most is **#1** — a routine `git checkout` can silently erase
|
||||
planning work because mutations live only in a gitignored DB and the
|
||||
pql-installed hooks rebuild that DB destructively. **#2** makes it worse by
|
||||
pointing users at the wrong file to commit. Fixing write-through (or a divergence
|
||||
guard) plus aligning the export docs would remove a whole class of "where did my
|
||||
tickets go" incidents.
|
||||
@@ -0,0 +1,240 @@
|
||||
# self-analysis.md — can Claude actually work inside clide?
|
||||
|
||||
**Date:** 2026-06-02
|
||||
**Author:** Claude (Opus 4.8), run as the dogfood agent against a live clide instance
|
||||
**Method:** This is not a documentation review. clide was running while I wrote this
|
||||
(socket `~/Library/Caches/clide/05cd448c962214d7.sock`, MCP SSE on `127.0.0.1:50354`,
|
||||
daemon reports `version 2.1.0`). I probed my own environment, drove the live daemon, and
|
||||
report what actually happened — with the command transcripts as evidence.
|
||||
|
||||
The question on the table: *we're close to working together inside clide — what's missing
|
||||
from my end?* Here's the honest answer.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
**The daemon is ready. My hands are missing.**
|
||||
|
||||
Everything the CLI-first contract (D-1, D-6) promises works end-to-end at the socket
|
||||
level — `git status`, `files`, `editor`, `pane`, exit codes, the lot. I verified it live.
|
||||
But a fresh Claude session dropped into this repo **cannot reach any of it**, because:
|
||||
|
||||
1. There is **no `clide` binary on `PATH`** — and no install path that would put one there.
|
||||
2. Nothing tells a fresh agent that clide is even running, where its socket is, or that
|
||||
the CLI exists.
|
||||
3. The live UI surfaces the user sees (the Claude pane, file tree, open files) are **not
|
||||
reflected** in the registries the CLI reads — `pane list` and `editor list` came back
|
||||
empty while clide was open and in use.
|
||||
|
||||
The first one is the blocker. The fix is roughly ten lines of Makefile. The other two are
|
||||
the difference between "the agent can issue commands" and "the agent and the user are
|
||||
actually looking at the same workspace."
|
||||
|
||||
---
|
||||
|
||||
## What works today (verified live)
|
||||
|
||||
I built the C client (`make clide-cli` — it had never been built; `native/macos-arm64/`
|
||||
did not exist) and pointed it at the running daemon:
|
||||
|
||||
```
|
||||
$ native/macos-arm64/clide ping
|
||||
{"pong":true,"ts":"2026-06-02T10:45:31Z","version":"2.1.0"} # exit 0
|
||||
|
||||
$ native/macos-arm64/clide git status
|
||||
{"branch":"main","upstream":"origin/main","ahead":0,"behind":0,
|
||||
"clean":false,"unstaged":[{"path":"governance/README.md",...}, ...]} # exit 0
|
||||
|
||||
$ native/macos-arm64/clide files root
|
||||
{"path":"/Users/jeroenschweitzer/Projects/clide","ignorePatterns":79} # exit 0
|
||||
```
|
||||
|
||||
- **IPC transport is solid.** Unix socket, JSON envelopes, the `_argv` bridge — all live.
|
||||
- **The command surface is real and broad.** `pane`, `files`, `editor`, `git`, `search`,
|
||||
`pql`, `panel` subsystems all dispatch. `git status` returned my actual working tree.
|
||||
- **Exit-code discipline is correct** (this matters for an agent — it's how I know if a
|
||||
command worked):
|
||||
|
||||
| command | exit |
|
||||
|---|---|
|
||||
| `clide ping` | `0` |
|
||||
| `clide git status` | `0` |
|
||||
| `clide editor open /nonexistent/path` | `1` |
|
||||
| `clide status` (not a real command) | `3` |
|
||||
|
||||
0/1/3 map cleanly onto the pql contract. Good. An agent can trust these.
|
||||
|
||||
So the foundation is genuinely there. The gaps below are about **delivery and
|
||||
observability**, not the core design.
|
||||
|
||||
---
|
||||
|
||||
## Gap 1 — `clide` is not on PATH, and nothing installs it there *(blocker)*
|
||||
|
||||
This is the one that stops us cold.
|
||||
|
||||
```
|
||||
$ which clide → clide not found
|
||||
$ clide ping → command not found (exit 127)
|
||||
```
|
||||
|
||||
The CLI-first contract assumes I run `clide …` from Bash. I can't. Digging in:
|
||||
|
||||
- The C client (`native/clide-cli/clide.c`) is the real CLI. It builds only via the
|
||||
**separate, non-default** target `make clide-cli`, and the output had never been built.
|
||||
- `make install` on **macOS** copies *only* the `.app` bundle to `~/Applications`. It
|
||||
**never places a `clide` CLI on PATH.**
|
||||
- `make install` on **Linux** symlinks `clide` → `$(INSTALL_PREFIX)/clide/clide`, which is
|
||||
the **GUI app binary** (the Flutter runner), *not* the C client. So even the Linux path
|
||||
doesn't deliver the shell client.
|
||||
|
||||
Net: there is **no supported way** for the `clide` command to exist on an agent's PATH.
|
||||
The contract that the entire agent-IDE relationship rests on has no delivery mechanism.
|
||||
|
||||
**Impact:** Total. Without this, "Claude works inside clide via the CLI" is aspirational.
|
||||
I only got there by reverse-engineering the socket path and compiling a C file myself.
|
||||
|
||||
**Fix (small):**
|
||||
- Make `clide-cli` a dependency of `build`/`install`.
|
||||
- On macOS `install`, also drop the built C client somewhere on PATH
|
||||
(`~/.local/bin/clide`, or `/usr/local/bin`), and have the GUI launch offer to install it
|
||||
(à la VS Code's "Install 'code' command in PATH").
|
||||
- Confirm the Linux symlink targets the **C client**, not the GUI binary.
|
||||
|
||||
---
|
||||
|
||||
## Gap 2 — No bootstrap: a fresh agent doesn't know clide is there
|
||||
|
||||
Even with the binary installed, a new session has no signal that it's hosted by clide.
|
||||
There's a discovery file for the *MCP* path (`~/.claude/ide/<pid>.lock`, which correctly
|
||||
pointed at workspace + SSE URL), but **nothing for the Bash/CLI path**:
|
||||
|
||||
- No `CLIDE_SOCK` / `CLIDE_WORKSPACE` env var in my shell.
|
||||
- No injected note (CLAUDE.md fragment, system reminder) saying "you're inside clide; use
|
||||
`clide …` to drive the editor, git panel, and file tree."
|
||||
- No pre-seeded `Bash(clide *)` allow rule mentioned anywhere the agent would see it.
|
||||
|
||||
I had to be *told* "you're running inside clide" and then go find the socket. That's not
|
||||
discoverable.
|
||||
|
||||
**Impact:** High. Discovery is the difference between a capability existing and a
|
||||
capability getting used. I won't reach for `clide editor open` if I don't know it's wired
|
||||
up.
|
||||
|
||||
**Fix:** When clide spawns/hosts an agent, export `CLIDE_SOCK`/`CLIDE_WORKSPACE`, ensure
|
||||
`clide` is on the child's PATH, and inject a short context note describing the CLI surface
|
||||
and the parity contract.
|
||||
|
||||
---
|
||||
|
||||
## Gap 3 — The live UI isn't visible to the CLI *(parity premise breaks here)*
|
||||
|
||||
D-6's promise is two-way: every UI affordance has a CLI verb, **and the agent can observe
|
||||
what the user is doing**. Right now I can't see the user's surfaces. While clide was open
|
||||
and you were talking to me through it:
|
||||
|
||||
```
|
||||
$ clide pane list → {"panes":[]}
|
||||
$ clide editor active → {"active":null}
|
||||
$ clide editor list → {"buffers":[]}
|
||||
```
|
||||
|
||||
Empty. Either the built-in UI panes (the Claude conversation pane, the file tree, any open
|
||||
viewer) **don't register into the daemon registries** the CLI reads, or those registries
|
||||
only track CLI-spawned entities. Either way, the consequence is the same: **I cannot tell
|
||||
what file you're looking at, what's selected, or what panes are open.** The "agent sees
|
||||
what the user sees" half of parity isn't there yet.
|
||||
|
||||
**Impact:** High for real collaboration. Half of working *together* is me reacting to
|
||||
what's on your screen ("you've got `dispatcher.dart` open — want me to jump to the handler
|
||||
that's failing?"). Today I'm blind to it.
|
||||
|
||||
**Fix:** Make the built-in extensions register their panes/buffers/active-file state
|
||||
through the same registries the `pane`/`editor` CLI reads. Add a `clide status` umbrella
|
||||
(see Gap 6) that returns a one-shot snapshot: active pane, focused file + selection, git
|
||||
summary, layout.
|
||||
|
||||
---
|
||||
|
||||
## Gap 4 — Event observation doesn't fit how an agent runs
|
||||
|
||||
`clide tail --events` is the design's answer to "how does Claude see state change." But a
|
||||
streaming, never-returning command is awkward from a request/response tool loop — I can't
|
||||
sit on an open stream the way a long-lived UI client can. I either background it and poll a
|
||||
file, or I miss events.
|
||||
|
||||
This is more ergonomic than broken, and it overlaps the still-open Q-2 (back-pressure) and
|
||||
Q-3 (event persistence/audit). But for *me specifically* it matters.
|
||||
|
||||
**Impact:** Medium. Without a pull-based form I'll just re-run `git status` / `editor
|
||||
active` on demand and never use the event bus — which means I miss things that happen
|
||||
between my polls.
|
||||
|
||||
**Fix:** Offer a cursor-based pull alongside the stream: `clide events --since <cursor>`
|
||||
returning everything since the cursor plus a new cursor. That fits an agent loop natively
|
||||
and dovetails with Q-3's persistence question.
|
||||
|
||||
---
|
||||
|
||||
## Gap 5 — Which Claude is the dogfood agent? *(needs a decision)*
|
||||
|
||||
There's an unresolved ambiguity I bumped straight into. My shell reports
|
||||
`TERM_PROGRAM=zed` — i.e. *this* Claude (me) is an external Claude Code harness, not a
|
||||
session clide spawned via the stream-json protocol (D-77/D-78). So there are two distinct
|
||||
"Claude inside clide" stories, and they have different gaps:
|
||||
|
||||
- **(A) clide-hosted session** — clide spawns `claude --output-format stream-json`, renders
|
||||
the conversation natively, handles permission prompts as native cards (D-77/D-78). This
|
||||
is the *user's* primary Claude pane.
|
||||
- **(B) external agent driving via CLI** — a Claude Code process (like me) that issues
|
||||
`clide …` commands to manipulate the IDE.
|
||||
|
||||
These aren't the same agent. In (A), the hosted Claude *is* the conversation but would
|
||||
itself need `clide` on PATH to drive the surrounding IDE (Gaps 1–3 apply to it too). In
|
||||
(B), clide can observe my `clide …` IPC calls but is blind to the rest of my tool use
|
||||
(file reads, `make test`, plain `git`) because my shell isn't clide-owned.
|
||||
|
||||
**Impact:** Medium, but foundational — it decides what "working together inside clide"
|
||||
even means. Worth a short governance note (Q- or D-record) pinning down the intended model:
|
||||
is the dogfood agent the hosted stream-json session, an external CLI driver, or both?
|
||||
|
||||
---
|
||||
|
||||
## Gap 6 — Minor / cleanup
|
||||
|
||||
- **No `clide status` command.** There's no single one-shot "what's the whole state right
|
||||
now" call — the natural first thing an agent reaches for. (`status` currently returns
|
||||
exit 3, unknown command.) Cheap to add and high-value for orienting.
|
||||
- **MCP transport is up but not reachable by me.** The SSE server is live
|
||||
(`:50354`), but `mcp__ide__*` tools aren't in my tool list this session, and
|
||||
`getDiagnostics`/`executeCode` were noted as stubs. So neither transport (CLI nor MCP) is
|
||||
actually wired to an external agent out of the box. The CLI path is the one to fix first
|
||||
(Gap 1); MCP can follow.
|
||||
- **Version drift cosmetic check:** daemon reports `2.1.0`; worth confirming that matches
|
||||
`pubspec.yaml` so an agent keying off `clide version` isn't misled.
|
||||
|
||||
---
|
||||
|
||||
## Minimum to actually dogfool (priority order)
|
||||
|
||||
1. **Ship `clide` on PATH.** Build the C client by default; install it to a PATH dir on
|
||||
macOS *and* Linux (targeting the C client, not the GUI binary). *(Gap 1 — blocker)*
|
||||
2. **Bootstrap the agent.** Export `CLIDE_SOCK`/`CLIDE_WORKSPACE`, ensure PATH, inject a
|
||||
context note + `Bash(clide *)` allow rule when clide hosts/launches an agent. *(Gap 2)*
|
||||
3. **Make the live UI observable.** Register built-in panes/buffers into the CLI-visible
|
||||
registries; add `clide status` for a one-shot snapshot. *(Gaps 3, 6)*
|
||||
4. **Add pull-based events** (`clide events --since`). *(Gap 4)*
|
||||
5. **Decide the agent model** in governance — hosted session vs external CLI driver vs
|
||||
both. *(Gap 5)*
|
||||
|
||||
Items 1–2 are small and unblock everything. With just those, I can drive the IDE from
|
||||
Bash today — I proved the daemon answers. Item 3 is what turns "I can issue commands" into
|
||||
"we're actually working in the same workspace."
|
||||
|
||||
---
|
||||
|
||||
*Everything above was checked against a running clide, not inferred from docs. The pleasant
|
||||
surprise is how little is actually broken: the hard part (a live, correct, single-process
|
||||
IPC contract with proper exit codes) is done and working. What's missing is the last mile
|
||||
that puts the tool in the agent's hands and lets the agent see the room.*
|
||||
Reference in New Issue
Block a user