Files
astrolabe/AGENTS.md
T

126 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Astrolabe Project
> **Purpose**: Onboarding document for AI agents (and humans) working on Astrolabe.
---
## Project Overview
**Astrolabe** is a browser-based snippet manager for Vega-Lite visualizations. A user keeps
a local library of **snippets** (saved Vega-Lite specs), edits each as JSON with live
validation and a live chart preview, and reuses **datasets** across many snippets. Fully
local, offline-capable, no account.
It is a **spec-driven rebuild** on an architecture adapted from its sibling project Syto.
The authoritative behavioral contract is **`docs/spec/`** (sections 0010). Implement *to
the spec*; do not port legacy code.
### Technical Stack
| Layer | Technology |
|-------|------------|
| Build | Vite, TypeScript, Vitest (happy-dom) |
| UI | React, Zustand, CSS Modules |
| Editor | Monaco (JSON + Vega-Lite schema service) |
| Charts | Vega-Lite + vega-embed |
| Storage | IndexedDB (snippets, datasets), localStorage (settings/prefs), URL hash (view state) |
| Offline | `vite-plugin-pwa` (Workbox), `registerType: 'prompt'` |
---
## Architecture (non-negotiable)
- **`src/core/` is portable** — no browser APIs, no React, no Monaco. All spec operations
live here and are tested hardest.
- **`src/app/`** — React + Zustand UI. State in Zustand **stores**; browser specifics in
**`src/app/infrastructure/`** adapters (IndexedDB / localStorage / URL hash). The rest of
the app never touches `window`/`indexedDB` directly.
- **Modals** go through a registry + coordinator + shell, not ad-hoc rendering.
- **CSS Modules + design tokens** (`styles/tokens.css`); themes flip `[data-theme]`.
- **No shared library with Syto** — patterns are adapted, never imported.
See [`docs/architecture/`](docs/architecture/00-overview.md) for the patterns behind each
layer (state, persistence, modals, routing, rendering, inference, relationships) and
`docs/IMPLEMENTATION-PLAN.md` for the milestone sequence. Both are **self-contained** — no
external repo is needed to work from them.
---
## Directory Structure
```
src/
├── core/ # Portable spec engine (no browser/React/Monaco)
├── app/
│ ├── components/ # React UI (CSS Modules co-located)
│ ├── stores/ # Zustand stores
│ ├── services/ # Business logic
│ ├── orchestration/ # Startup wiring: store↔adapter subscribers (persistence)
│ └── infrastructure/ # IndexedDB, localStorage, URL hash adapters
styles/ # Global CSS (tokens, base)
docs/
├── spec/ # Authoritative behavioral specification (0010) — the WHAT
├── architecture/ # Architecture playbook (0009) — the HOW (self-contained)
└── IMPLEMENTATION-PLAN.md
```
---
## Development
```bash
npm run dev # Dev server
npm run build # Typecheck + production build (+ PWA)
npm run typecheck # tsc --noEmit
npm test # Vitest (run once)
npm run test:watch # Vitest watch
npm run format # Prettier
```
### AI Developer Protocol
- **No git on your own initiative** — don't `add`/`commit`/`push` unless explicitly invited.
- **Verify** — run `npm run typecheck` and `npm test` after changes. A green build and a
smaller bundle prove nothing about behavior: when a change touches what the user sees or
does, confirm it by exercising the feature, not by the compiler alone.
- **Trim content, not capability** — when narrowing a third-party import or build to cut
size, remove optional _content_, never the library's _features_. The smallest/lowest-level
entry point is seldom the right one — it often drops capabilities you meant to keep. Prefer
the entry that excludes the unwanted content while retaining behavior, and validate the
behavior survived. (This bit us once: importing Monaco's `editor.api` to drop unused
languages also stripped every editor feature — see `docs/architecture/08`.)
- The line isn't "content vs. capability" by category — it's **"does any real user path
depend on this?"** Safe to drop: data no user path exercises (a date formatter's unused
locale tables, an icon set you never render, themes you don't ship). _Not_ safe, even
though it looks like "content": **human-language coverage** — font script subsets,
translatable strings — which is capability the moment the app is meant to be usable in
that language. Treat dropping it like dropping a feature. (This bit us a second time:
trimming IBM Plex to the latin subsets dropped Cyrillic — capability for an
internationally-usable app. We ship every script subset and precache them for offline;
`unicode-range` means the browser only downloads what a glyph needs anyway.)
- **Spec is the contract** — when in doubt, read `docs/spec/`. If the spec is wrong or
silent, raise it; change the spec deliberately rather than drifting from it.
- **Core-first** — for each feature, build the pure `src/core/` logic with tests before UI.
### Project skills
Invoke with `/<name>` (defined in `.claude/skills/`):
- **`/alignment`** — review uncommitted/staged changes for quality, test coverage, and
alignment with `docs/spec/` + `docs/architecture/`. Fixes issues directly and leaves
`// TODO:` breadcrumbs at code sites for out-of-scope observations.
- **`/doc-update`** — capture session-discovered knowledge gaps into the right doc layer
(`docs/spec/` for behavior, `docs/architecture/` for patterns).
- **`/release`** — bump version, update the changelog, prepare a git tag.
### Versioning
Simplified semver `0.x.y` (pre-1.0): minor for features/behavior, patch for fixes. Single
source of truth is `version` in `package.json`, injected as `__APP_VERSION__`.
### Testing Philosophy
High coverage on `src/core/` (parsing, detection, profiling, reference resolution, fit
transforms, import normalization). Lighter on components. Extract testable logic out of
components into core/stores where practical.