CLAUDE.md · git:20260515.73dd2f2 · 2026-05-15 · sha256 3b564130b714e0d5
CLAUDE.md git:20260515.73dd2f2A
Immutable. This exact content never changes and is served at /api/v1/blob/3b564130b714e0d5.
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) 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 ``` `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`: 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. Cross-cutting modules: - `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`. Type contracts live in `src/types.ts` (domain: `Category`, `CreatedList`) and `src/api/types.ts` (GitHub API shapes). ## Constraints worth remembering before changing behavior - 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.