diff --git a/.claude/skills/git-commit/SKILL.md b/.claude/skills/git-commit/SKILL.md index 9d653b3c..7f057d4e 100644 --- a/.claude/skills/git-commit/SKILL.md +++ b/.claude/skills/git-commit/SKILL.md @@ -63,10 +63,10 @@ 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). +3. Bump `pubspec.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. +`pubspec.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 `pubspec.yaml` and the changelog out of sync is the mistake this rule prevents. ## Attribution trailer diff --git a/CHANGELOG.md b/CHANGELOG.md index 699f555e..0197fde7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,10 @@ 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:`, +Versions are tracked in [`pubspec.yaml`](pubspec.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. +heading, and (b) bumping `pubspec.yaml` `version:` in the same commit. ## [Unreleased] @@ -404,7 +404,7 @@ heading, and (b) bumping `project.yaml` `version:` in the same commit. - Go sidecar skeleton under `sidecar/` — `cmd/clide/main.go`, `go.mod`, and the `internal/*` packages (`cli`, `daemon`, `diag`, `git`, `ipc`, `pql`, `proc`, `pty`, `version`). Deleted wholesale per [ADR 0005](docs/ADRs/0005-dart-core-ptyc-peer.md): the "sidecar language: Go" premise no longer holds once the core is Dart. All functionality listed for those packages will be reimplemented under `lib/` as part of Tier 0. - Go-specific Makefile targets (`lint`, `vuln`, `test-race`, `fmt`, `tidy`, `snapshot`, `tools`, `install` via Go), the `govulncheck`/`goimports`/`golangci-lint` version pins, and the pre-push hook's `GOBIN` PATH injection. Replaced with Dart/Flutter equivalents (`analyze`, `format`, `test`, `test-integration`, `build` via `dart compile exe`). -- `module:` and `go_version:` from `project.yaml` — single-language core means no Go module path to track. +- `module:` and `go_version:` from `pubspec.yaml` — single-language core means no Go module path to track. ### Changed @@ -450,14 +450,14 @@ heading, and (b) bumping `project.yaml` `version:` in the same commit. [ADR 0004](docs/ADRs/0004-ignore-file-strategy.md) — Ignore file strategy (`ignore_files:` in `.pql/config.yaml`, layered). - Pre-push quality gate: `.githooks/pre-push` runs `make push-check` (lint + test + test-race + test-integration + vuln + app-analyze + app-test) so bad pushes are caught locally before they hit Gitea. The app-side targets gracefully noop until Flutter is scaffolded. Install with `make hooks` (sets `git config core.hooksPath .githooks`); the hook prepends `$GOBIN`/`$HOME/go/bin` to PATH so govulncheck resolves without the user touching their shell profile. - Go sidecar/CLI skeleton under `sidecar/` (module `git.schweitz.net/jpmschweitzer/clide/sidecar`): `cmd/clide/main.go`, `internal/cli` with a stdlib-flag dispatch, `internal/diag` mirroring pql's exit-code + stderr-JSON contract, `internal/version` with ldflag-stamped build info, and placeholder packages for `daemon`, `pty`, `proc`, `git`, `ipc`, `pql` awaiting their tier. `clide --version` emits JSON build-info today. -- Root `Makefile` drives both the Go sidecar and the Flutter app under one toolchain. Version is read from `project.yaml` via awk and stamped into the sidecar via `-ldflags -X`. Flutter targets gracefully noop before the app is scaffolded so the Makefile is usable from day one. Pinned Go tooling (govulncheck, goimports, golangci-lint) installs via `make tools`. +- Root `Makefile` drives both the Go sidecar and the Flutter app under one toolchain. Version is read from `pubspec.yaml` via awk and stamped into the sidecar via `-ldflags -X`. Flutter targets gracefully noop before the app is scaffolded so the Makefile is usable from day one. Pinned Go tooling (govulncheck, goimports, golangci-lint) installs via `make tools`. - `ci/` entry scripts: `test.sh`, `lint.sh` (includes the supply-chain gate — no green lint without a green CVE scan), `security.sh`, `release.sh` (stub). -- Project identity files for the Flutter rebuild at the repo root: `project.yaml` (single source of truth for version + module path, version 2.0.0-dev), a fresh `README.md`, MIT `LICENSE`, and `.editorconfig`. The Python clide's manifest and README are preserved under `legacy/`. +- Project identity files for the Flutter rebuild at the repo root: `pubspec.yaml` (single source of truth for version + module path, version 2.0.0-dev), a fresh `README.md`, MIT `LICENSE`, and `.editorconfig`. The Python clide's manifest and README are preserved under `legacy/`. - [`docs/initial-plan.md`](docs/initial-plan.md) — the north-star design document for the Flutter rebuild. Captures what we kept from Python Clide (pane model, git skills, Claude-always-visible), what we took from Obsidian (canvas and graph — no vault, no bases, no plugin inheritance), what Claudian's short experiment contributed (Go sidecar, CLI-first, pql-as-subsystem, ignore-file strategy), and the tier roadmap (Tier 0 app+sidecar handshake → Tier 5 canvas+graph). - [`CLAUDE.md`](CLAUDE.md) orientation doc for future Claude Code instances: project identity, guardrails as one-liners, tier ordering, parent-project pointers, commands, dependencies & supply chain, open questions. Points at the design doc and ADRs rather than restating their content. - 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 + `pubspec.yaml`-and-changelog-bumped-together rule, attribution trailer, safety reminders). diff --git a/CLAUDE.md b/CLAUDE.md index 53c0e095..a254ff56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,7 +80,7 @@ One-time setup on a fresh clone: `make hooks && flutter pub get` once Flutter is ## Changelog discipline -[Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). Every user-visible commit adds an entry under `## [Unreleased]` in [`CHANGELOG.md`](CHANGELOG.md). Cutting a release means moving Unreleased entries under a new dated version heading **and** bumping `project.yaml` `version:` in the same commit — see [`.claude/skills/git-commit/SKILL.md`](.claude/skills/git-commit/SKILL.md) for the full rule. +[Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). Every user-visible commit adds an entry under `## [Unreleased]` in [`CHANGELOG.md`](CHANGELOG.md). Cutting a release means moving Unreleased entries under a new dated version heading **and** bumping `pubspec.yaml` `version:` in the same commit — see [`.claude/skills/git-commit/SKILL.md`](.claude/skills/git-commit/SKILL.md) for the full rule. ## Open questions diff --git a/Makefile b/Makefile index 7a86ac63..02c5867e 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ INSTALL_DIR ?= $(HOME)/.local/bin -VERSION_BASE ?= $(shell awk -F': *' '/^version:/ {gsub(/[" ]/,"",$$2); print $$2; exit}' project.yaml) +VERSION_BASE ?= $(shell awk -F': *' '/^version:/ {gsub(/[" ]/,"",$$2); print $$2; exit}' pubspec.yaml) COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DIRTY := $(shell git diff --quiet HEAD 2>/dev/null || echo .dirty) VERSION ?= $(VERSION_BASE)+$(COMMIT)$(DIRTY) diff --git a/decisions/architecture.md b/decisions/architecture.md index 40ad0401..e8b172b6 100644 --- a/decisions/architecture.md +++ b/decisions/architecture.md @@ -108,7 +108,7 @@ Core, rendering, IPC, kernel, panel manager. - **Date:** 2026-04-20 (was ADR 0006) - **Decision:** The CLI is organised into **subsystems**. Each subsystem owns a noun, a set of verbs, and a set of events. The set is closed at any point in time (documented); growth is additive (new verbs, new events — never renaming existing ones without a version bump). Initial subsystems (by tier): `pane`, `tab`, `open`, `editor`, `panel`, `tree`, `git`, `pql`, `canvas`, `graph`, `theme`, `settings`, `project`. Two umbrella entry points sit outside any subsystem: `clide tail --events [--filter [:]]` and `clide status`. Command shape: `clide [...] [--flag ...] [-- argv...]`. Exit codes parity with pql (`0/1/2/3/4` + `64-78` sysexits reserved); diagnostic JSON on **stderr** on non-zero exit; stdout stays machine-parseable on success. Events are JSON objects, one per line, with `v`, `ts`, `type` (`.`), `subsystem`, `id`, and `payload`; binary payloads base64. Every state-changing command emits at least one event; read-only commands emit nothing. Replay buffer per subsystem (default depth 16) so late subscribers still see recent effects. Parity rule: every UI affordance has a matching CLI verb (or a follow-up task naming the verb); every CLI verb surfaces in the UI (or documents why it's Claude-only). - **Context:** [D-001](#d-001-cli-first-not-mcp) established that Claude drives clide via a Bash CLI. That decided the *channel* — it did not define the *surface*. CLAUDE.md stated the rule colloquially ("every CLI subcommand has a UI affordance … if you add one side without the other, the feature is incomplete"); this record restates it as an implementable contract that satisfies user/Claude parity, daemon-as-authoritative-state, and pql-style ergonomics at once. -- **Rationale:** Surface is enumerable — adding a subsystem means adding a row and specifying verbs + events. Wire schema is versioned (`v: 1` starting point; compatibility breaks bump the major and land alongside a `project.yaml` `schema_version:` bump — see [Q-005](questions-architecture.md#q-005-ipc-wire-format-stability)). Events are the only UI→app state channel; the Flutter app does not poll. Extensions inherit this — a Dart extension publishes a subsystem; the same registration pipeline exposes it to Claude via the CLI. +- **Rationale:** Surface is enumerable — adding a subsystem means adding a row and specifying verbs + events. Wire schema is versioned (`v: 1` starting point; compatibility breaks bump the major and land alongside a `pubspec.yaml` `schema_version:` bump — see [Q-005](questions-architecture.md#q-005-ipc-wire-format-stability)). Events are the only UI→app state channel; the Flutter app does not poll. Extensions inherit this — a Dart extension publishes a subsystem; the same registration pipeline exposes it to Claude via the CLI. - **Cost:** Replay-buffer memory per subsystem (cheap — most emit seldom). Back-pressure on firehose streams ([Q-002](questions-architecture.md#q-002-back-pressure-on-event-streams)), authorisation granularity ([Q-001](questions-architecture.md#q-001-authorisation-granularity)), and event persistence ([Q-003](questions-architecture.md#q-003-event-persistence-audit-undo)) are all deferred until Tier 1 is in real use. - **Raised by:** 2026-04-20 planning. diff --git a/decisions/process.md b/decisions/process.md index 11c97ada..48ea514a 100644 --- a/decisions/process.md +++ b/decisions/process.md @@ -34,7 +34,7 @@ Q&D record system itself, kanban, commit conventions, changelog. ### D-038: Changelog discipline — Keep a Changelog 1.1.0 - **Date:** 2026-04-21 -- **Decision:** `CHANGELOG.md` follows Keep a Changelog 1.1.0. Every user-visible commit adds an entry under `## [Unreleased]` in the appropriate subsection (Added / Changed / Deprecated / Removed / Fixed / Security). Cutting a release moves entries under a dated heading and bumps `project.yaml` `version:` in the same commit. Pure bookkeeping commits (comment-only, .gitignore tweak, lint config) skip the changelog. +- **Decision:** `CHANGELOG.md` follows Keep a Changelog 1.1.0. Every user-visible commit adds an entry under `## [Unreleased]` in the appropriate subsection (Added / Changed / Deprecated / Removed / Fixed / Security). Cutting a release moves entries under a dated heading and bumps `pubspec.yaml` `version:` in the same commit. Pure bookkeeping commits (comment-only, .gitignore tweak, lint config) skip the changelog. - **Rationale:** Release notes that have to be written after the fact aren't written. Writing them per commit keeps the log honest. - **Cost:** One extra edit per user-visible commit; zero if the change is invisible. - **Raised by:** 2026-04-21 planning. diff --git a/decisions/questions-architecture.md b/decisions/questions-architecture.md index 99f826a9..82943227 100644 --- a/decisions/questions-architecture.md +++ b/decisions/questions-architecture.md @@ -31,7 +31,7 @@ ticket persistence. ### Q-005: IPC wire-format stability + `schema_version:` - **Status:** Open -- **Question:** When do we freeze the IPC envelope / schema and introduce `schema_version:` in `project.yaml`? What's the bump policy for breaking changes? +- **Question:** When do we freeze the IPC envelope / schema and introduce `schema_version:` in `pubspec.yaml`? What's the bump policy for breaking changes? - **Context:** Covered partially by [D-006](architecture.md)'s `v: 1` starting point; CLAUDE.md flags this as "decide when the first real subcommand lands." - **Source:** CLAUDE.md "Open questions" footer. diff --git a/decisions/questions.md b/decisions/questions.md index 83f3ff88..86880088 100644 --- a/decisions/questions.md +++ b/decisions/questions.md @@ -18,7 +18,7 @@ open questions with one-line summaries. - **[Q-021](questions-process.md#q-021-pql-absorbs-planning-vs-keeps-separate)** — Pql absorbs planning features vs clide absorbs pql vs separate CLI. Blocks the stopgap sunset and shapes the pql-side planning session. - **[Q-022](questions-process.md#q-022-ticket-persistence-strategy)** — Ticket persistence: per-dev only / milestone-committed / markdown-mirrored. Shapes multi-contributor story. -- **[Q-005](questions-architecture.md#q-005-ipc-wire-format-stability)** — IPC wire-format stability and `schema_version:` in `project.yaml`. Decide when the first real subcommand lands. +- **[Q-005](questions-architecture.md#q-005-ipc-wire-format-stability)** — IPC wire-format stability and `schema_version:` in `pubspec.yaml`. Decide when the first real subcommand lands. - **[Q-015](questions-process.md#q-015-editor-tab-full-lsp-vs-tree-sitter-only)** — Editor tab: full LSP integration vs tree-sitter-only highlight. Decide during Tier 2. --- diff --git a/project.yaml b/project.yaml deleted file mode 100644 index 42015725..00000000 --- a/project.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# clide — project manifest -# -# Single source of truth for project metadata. Read by: -# - the Makefile (VERSION ldflag for the sidecar) -# - the Flutter app's build-info surface -# - any future Claude Code skill (compatibility check) -# - any other consumer that needs to know "what is this project, -# what version of it is on disk right now" -# -# Convention: this file declares the version the codebase *claims to be*. -# Local `make build` stamps that version + git short SHA + dirty marker -# into the sidecar binary and (when wired) into the Flutter app. -# Tagged releases use the git tag for binaries; project.yaml `version:` -# is bumped in the post-release commit alongside the changelog move. -# -# Lineage: Python clide reached v1.2.0 under legacy/. The Flutter -# rebuild starts fresh at v2.0.0-dev to signal a clean break. - -name: clide -description: Flutter desktop IDE for Claude Code — markdown-first, pql-powered, with a Go sidecar. -version: 2.0.0-dev -status: pre-v2.0, scaffolding (Tier 0 — Flutter app + sidecar handshake — is next) - -repository: ssh://git@git.schweitz.net:2222/jpmschweitzer/clide.git -license: MIT - -# Toolchain pins. Mirror in pubspec.yaml when bumping. -# Single-language core — Dart + Flutter. Native supporter tools -# (ptyc today, peers tomorrow) pin their own toolchains in their own -# directories; not tracked here. -flutter_channel: stable -dart_sdk: ">=3.5.0 <4.0.0" - -maintainers: - - name: Jeroen Schweitzer - email: jpmschweitzer@gmail.com - -keywords: - - ide - - flutter - - claude-code - - markdown - - pql - - canvas - - graph - - agent-tools diff --git a/pubspec.yaml b/pubspec.yaml index e07a33f9..167c8bc7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,8 @@ # clide — Flutter desktop IDE for Claude Code. # -# Single package: UI, core subsystems (IPC, PTY, git, pql), and -# extensions all live here. The Flutter app hosts the IPC server -# in-process (D-056); tmux owns session persistence (D-041). +# Single source of truth for project metadata and dependencies. +# The Flutter app hosts everything in-process (D-056); tmux owns +# session persistence (D-041). # # Prefer-zero-deps; every third-party entry is exact-pinned and # justified. No carets. See D-031. @@ -16,6 +16,17 @@ publish_to: none version: 2.0.0-dev repository: https://git.schweitz.net/jpmschweitzer/clide +# Project metadata (was project.yaml, folded in per D-056). +# version: above is the single source of truth. The Makefile reads +# it for build stamping. Cutting a release bumps version + changelog +# in one commit. +# +# maintainers: +# Jeroen Schweitzer +# license: MIT +# status: pre-v2.0, interaction model + panel system landed +# flutter_channel: stable + environment: sdk: ">=3.5.0 <4.0.0" flutter: ">=3.19.0"