CLAUDE.md · diff

git:20260515.73dd2f2 to git:20260929.3e33c69

36 added, 36 removed. Audit A to A.

# CLAUDE.md
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+ This file provides guidance to Claude Code and other agent hosts when working with code in this repository.
## Commands
- Build and run (Bun is the build tool; Node ≥18 is the runtime target):
-
```bash
- bun install # install deps
- bun run dev # run CLI from src/index.ts (no build)
- bun run start # alias of dev
- bun run build # bundle to dist/index.js (ESM, node target)
- node dist/index.js <command> # run built CLI
+ bun install # install dependencies
+ bun run typegen # compile JSON Schemas to src/generated/
+ bun run build # bundle CLI into dist/index.js (ESM, Node >=22 target)
+ bun test # run unit and integration tests
+ node dist/index.js <command> # run built CLI via Node
```
- `npm install -g .` or `npm link` after build to expose the `startidy` bin globally.
-
- There is no test runner, linter, or formatter configured. `npm run prepublishOnly` runs `npm run build` (note: package.json mixes `bun build` and `npm` script names — building requires Bun installed).
-
- ## Runtime configuration
-
- The CLI reads credentials from three sources, with this precedence: CLI flags → environment variables → `.env` in CWD (loaded via `dotenv` at `src/index.ts`). Required vars: `GITHUB_TOKEN`, `GITHUB_USERNAME`, `GEMINI_API_KEY`. Tunables (see `src/utils/config.ts` and README): `MAX_CATEGORIES` (cap 32 — GitHub's hard limit), `CLASSIFY_BATCH_SIZE`, `BATCH_DELAY`, `GEMINI_MODEL`, `GEMINI_RPM`, `LIST_IS_PRIVATE`, `DEBUG`.
-
- CLI flags are pushed back into `process.env` in a Commander `preAction` hook before subcommands run, so downstream code reads everything via `loadConfig()`.
-
- ## Architecture
-
- The CLI organizes a user's GitHub Stars into GitHub Lists using Gemini for both category planning and per-repo classification. The pipeline is intentionally split into four idempotent steps that can be run individually or chained via `run`:
+ ## Architecture (v2)
- 1. **plan** (`src/commands/plan.ts` + `services/gemini.ts` + `prompts/category-planner.ts`) — fetches all starred repos, asks Gemini to design up to 32 categories using `Major: Minor` names (≤20 chars, GitHub List name limit), and persists the result via `utils/plan-storage.ts` to `.stardust-plan.json`.
- 2. **create-lists** (`src/commands/create-lists.ts`) — reads the saved plan and creates the corresponding GitHub Lists via `api/lists.ts`. `--force` allows partial creation when some Lists already exist.
- 3. **classify** (`src/commands/classify.ts` → `services/classifier.ts`) — batches repos (default 20), fetches each README (`api/readme.ts`), runs `GeminiService.classifyRepositoriesBatch` with the planned categories, then attaches each repo to its target Lists via GitHub's GraphQL `addRepoToGitHubLists`. `--use-existing` lets classify operate against the live Lists without a plan file; `--only-new` skips already-classified repos; `--reset` detaches everything.
- 4. **run** (`src/commands/run.ts`) — orchestrates plan → delete-existing-Lists (interactive prompt) → create-lists → classify in one shot; `--only-new` and `--dry-run` are honored.
+ Startidy is a contract-driven GitHub Stars organizer. It delegates planning, categorizing, and user interaction to the host agent while providing a deterministic, safe, and verifiable CLI for GitHub reads and writes.
- Cross-cutting modules:
+ ```text
+ User ⇄ Host Agent / Skill
+ │ (reads snapshot, classifies repos, constructs plan.json)
+ ▼
+ startidy CLI
+ │ (parses args, validates JSON Schema/policy, produces review.json, executes)
+ ▼
+ core (pure domain logic: ports, snapshot, candidates, plan, policy, diff, executor)
+ ▼
+ adapters (github-gh via `gh api`, file-store with account isolation & locking)
+ ```
- - `src/api/` — thin GitHub client. `client.ts` is a shared fetch wrapper with auth/retry; `lists.ts` and the `addRepoToGitHubLists`/`getRepositoryNodeId` helpers use GitHub's GraphQL API (Lists are not exposed in REST). `repos.ts` paginates starred repos; `readme.ts` fetches raw README content.
- - `src/services/gemini.ts` — wraps `@google/genai`, handles JSON-mode prompting and parsing for both planner and classifier prompts in `src/prompts/`.
- - `src/utils/rate-limiter.ts` — provides `delay`, `retryWithBackoff` (used around every GitHub mutation in `classifier.ts`), and `runWithConcurrency` (5-way parallel List attach within a batch).
- - `src/utils/update-checker.ts` — non-blocking npm version check fired from `index.ts`.
+ ### Three-Phase Pipeline
- Type contracts live in `src/types.ts` (domain: `Category`, `CreatedList`) and `src/api/types.ts` (GitHub API shapes).
+ 1. **Read**:
+ - `startidy doctor --json`: Diagnoses Node, gh CLI, and GitHub authentication.
+ - `startidy snapshot --out snapshot.json --json`: Captures starred repos, user lists, memberships, and candidates.
+ - `startidy details --snapshot snapshot.json --candidates --offset 0 --limit 20 --out details.json --json`: Retrieves README contents in manageable batches.
+ 2. **Plan & Review**:
+ - Agent formulates categories and decisions conforming to `src/schemas/plan.schema.json`.
+ - `startidy preview --snapshot snapshot.json --plan plan.json --out review.json --json`: Validates schema, references, scope, and policy; generates cryptographic digest and diff operations.
+ 3. **Execution & Recovery**:
+ - `startidy apply --review review.json --json`: Executes verified operations against GitHub under an account lock.
+ - `startidy status --run <runId> --json`: Inspects execution journal.
+ - `startidy apply --resume <runId> --json`: Safely resumes partial executions without duplicating verified operations.
- ## Constraints worth remembering before changing behavior
+ ### Data Contracts
- - GitHub Lists cap: **32 Lists** per user, **20 chars** per List name. The planner prompt and `MAX_CATEGORIES` enforcement both depend on this.
- - Gemini Free tier defaults to 15 RPM; the batch loop uses `BATCH_DELAY` between batches and `runWithConcurrency(..., 5)` inside batches — changing either can trigger 429s.
- - All List CRUD goes through GraphQL; there is no REST fallback. `getRepositoryNodeId` is required because the GraphQL mutation needs the global node ID, not `owner/repo`.
- - `tsconfig.json` includes `github-lists-api.ts` at the repo root which does not currently exist — leftover include; safe to ignore but don't rely on it.
+ - `src/schemas/snapshot.schema.json`: Normalized user state, lists, repos, and candidates.
+ - `src/schemas/plan.schema.json`: Change intent (`bootstrap`, `incremental`, `targeted`, `full`).
+ - `src/schemas/review.schema.json`: Review binding plan, snapshot baseline, atomic operations, digest, and summary.
+ - Types in `src/generated/` are strictly generated via `bun run typegen`. Do not edit them by hand.