CLAUDE.md · git:20261011.398949e · 2026-10-11 · sha256 fb3383247b281db9
CLAUDE.md git:20261011.398949eA
Immutable. This exact content never changes and is served at /api/v1/blob/fb3383247b281db9.
# CLAUDE.md Working notes for AI agents in the Scout monorepo. ## This repo holds two shipping artifacts | Path | Artifact | Read next | |---|---|---| | `plugin/` | The Scout Claude Code plugin + Python engine (`scoutctl`) | `plugin/CLAUDE.md` | | `apps/macos/` | The Scout macOS menu-bar app (SwiftUI) | `apps/macos/CLAUDE.md` | **Work in the subtree that owns the change, and read that subtree's `CLAUDE.md` first.** The two have different languages, test runners, and release flows. ## Rules that span both subtrees - **`.claude-plugin/marketplace.json` lives at the REPO ROOT**, not in `plugin/`. `claude plugin marketplace add` reads it from there. `plugin.json` — the canonical version — lives at `plugin/.claude-plugin/plugin.json`. Its scout entry pins a `git-subdir` source to the **`stable` branch** (#362), so installs get the latest release, never `main`'s tip. Only `release.sh finalize` moves `stable`. Never point the entry back at `"./plugin"`, and never push `stable` by hand except to run the recovery command `finalize` prints. - **Everything the plugin needs at runtime must stay under `plugin/`.** `CLAUDE_PLUGIN_ROOT` resolves to the materialized `plugin/` subtree only; a plugin file that reaches outside it is broken for every installed user, and nothing in this repo will tell you. - **One version, one tag, one release.** Scout's app and plugin share one version `X.Y.Z`. It lives in `plugin/.claude-plugin/plugin.json`, the root `marketplace.json`, `plugin/engine/pyproject.toml`, `plugin/engine/scout/__init__.py`, and every `MARKETING_VERSION` in `apps/macos/Scout.xcodeproj`; `versioning check` (CI: `contract`) fails on drift. From v0.16.0 every release is ONE tag `vX.Y.Z`, cut with `scripts/release.sh prepare` then `finalize`; release candidates are `vX.Y.Z-rc.N`, cut with `rc` from `release/vX.Y.Z`. Never create `app/v*` or `plugin/v*` tags (sole exception before v0.16.0: an urgent `plugin/v0.15.x` patch via `plugin/scripts/release-plugin.sh`); the existing ones (`app/v0.1.0`–`app/v0.14.0`, `plugin/v0.14.0`, `plugin/v0.15.0`) are history. The app was never released as 0.15.0. Bare `v0.4.0`–`v0.13.0` are the plugin's pre-monorepo releases. Agents never run `finalize`/`rc` for real. - **Issue and PR numbers come from two repos.** This repo is the former `Raven-Scout/scout-plugin`, renamed `Raven-Scout/Scout` when the app moved in, so its own `#N` numbering is scout-plugin's. The old app repo is `Raven-Scout/scout-app-legacy` (archived). A bare `#N` in `apps/macos/` files or in a pre-move app commit subject, and any `Raven-Scout/Scout#N` written before the move, means `Raven-Scout/scout-app-legacy#N`. Link old app items there; never rewrite them to a bare `#N` here. - **Contract artifacts are generated, never hand-edited.** The connector roster and schedule snapshot each have ONE canonical file under `plugin/engine/scout/`, generated from its `.yaml`, and every client copy under `apps/*/` is a byte copy of it. To change one, from `plugin/engine`: edit `scout/connectors.yaml` (or `scout/defaults/schedule.yaml`), regenerate the canonical file with `.venv/bin/python -m scout.scripts.connectors_snapshot --no-also-write-app-fixture` (or `schedule_snapshot`), then from the repo root `cp` it over every client copy `contract.yml` checks. **Always pass `--no-also-write-app-fixture`** — the default also writes into a sibling `~/scout-app` checkout outside this repo, and never into `apps/`. `contract.yml` fails the build if a copy drifts. See `docs/superpowers/specs/2026-09-03-monorepo-consolidation-design.md` §7. - **The parser corpus has one canonical copy too:** `plugin/engine/tests/fixtures/contract/parser-corpus.json`. Edit it, set `EXPECTED_SHA256` (`plugin/engine/tests/unit/test_parser_corpus_checksum.py`) and `canonicalSHA256` (`apps/macos/ScoutTests/ActionItems/ParserContractTests.swift`) to its new `shasum -a 256`, then `cp` it to `apps/macos/ScoutTests/Fixtures/parser-corpus.json` — all in one commit. (scout-iOS-app vendors a copy in its own repo; see `apps/macos/CLAUDE.md`.) - **Never edit a `*.snapshot.json` by hand.** That is what broke the shipped connector roster for four months. - **Plugin history was absorbed with `git subtree`, SHAs preserved.** `git blame plugin/<file>` crosses the merge to the original commits, but `git log -- plugin/<file>` stops at the merge commit — for a plugin file's earlier history run `git log <subtree-merge>^2 -- <path without the plugin/ prefix>` (the first subtree merge is the commit titled "absorb scout-plugin into plugin/"). ## Cross-cutting changes A change touching both subtrees (a new `scoutctl` subcommand the app calls, a snapshot schema change) lands as ONE commit, and `contract.yml` is the gate. That is the entire reason these repos were merged — do not split such a change across two PRs out of habit.