Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Source of truth for AI agent configuration. Cursor consumes via symlinks in `.cu
| Tier 1 / 2 / 3 attachment modes | [rules/agents-tier-system.md](rules/agents-tier-system.md) |
| Persist tier/pairing deltas | [skills/writing-agents-config](skills/writing-agents-config/SKILL.md) |
| Authoring new rules/skills (meta) | [`writing-great-skills`](skills/writing-great-skills/SKILL.md) |
| Product north-star (tenets) | [`product-tenets`](skills/product-tenets/SKILL.md) |
| Past corrections | [`lessons.md`](lessons.md) |
| What exists on disk right now | `ls .agents/rules` · `ls .agents/skills` |

Expand All @@ -28,7 +29,7 @@ Discover on disk via `ls` + the frontmatter audit in [`agents-tier-system`](rule

## Conventions

- **`-priming` suffix** when a Tier-2 rule filename ≠ skill folder name (`docs-governance-priming` ↔ `docs-governance` + `docs-lifecycle-sweep`; `architecture-priming` ↔ `improve-codebase-architecture`).
- **`-priming` suffix** when a Tier-2 rule filename ≠ skill folder name (`docs-governance-priming` ↔ `docs-governance` + `docs-lifecycle-sweep`; `docs-voice-priming` ↔ `docs-voice`; `architecture-priming` ↔ `improve-codebase-architecture`).
- **No `AGENTS.md` in skill folders** — use `FULL-GUIDE.md` or topic siblings (`WORKFLOW.md`, `REFERENCE.md`, `LANGUAGE.md`, `PROSE.md`) for bulk reference. Repo root `AGENTS.md` is a thin stub only.
- **Thin rules** (~10–40 lines); depth in `SKILL.md` or siblings.

Expand Down
2 changes: 2 additions & 0 deletions .agents/lessons.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ alwaysApply: true

- npm trusted publishing (OIDC) needs npm ≥ 11.5.1 + Node ≥ 22.14; oven-sh/setup-bun leaves npm 10.x in PATH, so a release job running `changeset publish`/`npm publish` must also run actions/setup-node (Node 24 → npm 11) or OIDC isn't detected → ENEEDAUTH.
- Don't pin a GitHub action to a moving major tag's commit SHA (e.g. setup-node@<v6-tag-commit>) — the tag moves and orphans/GCs the commit → "unable to find version"; pin to an immutable release-tag commit or use the moving @vN tag.
- Docs `docs:audit` with `deployment.base` (e.g. `/persist`) skips `canonical_bad_target` + `non_canonical_in_sitemap` + `indexable_page_not_in_sitemap` until upstream fixes canonical vs stripped `page.url`; re-evaluate on docs-toolchain bumps.
- Format `apps/docs` non-content at `printWidth: 80` via nested `apps/docs/.oxfmtrc.json` (nearest-config-wins); keep `content/**` ignored so oxfmt cannot collapse `:::note`/`:::tip` fences (oxfmt Markdown bug — [Blume FAQ](https://useblume.dev/docs/faq#why-is-oxfmt--ultracite-collapsing-my-directives)); lint-staged must list `mdx` or content-only commits skip format entirely.
2 changes: 1 addition & 1 deletion .agents/rules/agents-tier-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ alwaysApply: false

Three attachment modes: **always-on** (`alwaysApply: true`), **auto-attached** (`globs:`), **intent** (`description:` only).

**Tier 1 budget:** owner-set; currently 8 always-on rules + `lessons.md` (≤250 lines total). The frontmatter audit is the source of truth — **no hardcoded Tier 1 name lists** in rule, skill, or README. Audit:
**Tier 1 budget:** owner-set; run the audit below for the always-on count (+ `lessons.md` 250 lines combined). **No hardcoded Tier 1 name lists** in rule, skill, or README. Audit:

```bash
for f in .agents/rules/*.md .agents/lessons.md; do
Expand Down
4 changes: 2 additions & 2 deletions .agents/rules/docs-governance-priming.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ alwaysApply: false

Before authoring or editing any doc, **read the [`docs-governance` skill](../skills/docs-governance/SKILL.md)**.

Lifecycle types, existence test, anti-bloat, and cross-reference discipline live in the skill — not duplicated here.
Lifecycle types, existence test, anti-bloat, README surfaces (`apps/docs` canonical; root README is npm landing), and cross-reference discipline live in the skill — not duplicated here.

Janitor sweep: [`docs-lifecycle-sweep`](../skills/docs-lifecycle-sweep/SKILL.md).
Janitor sweep: [`docs-lifecycle-sweep`](../skills/docs-lifecycle-sweep/SKILL.md). Public site sync after merges: [`update-docs`](../skills/update-docs/SKILL.md).
14 changes: 14 additions & 0 deletions .agents/rules/docs-voice-priming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
description: Docs voice primer — read docs-voice skill before authoring apps/docs prose.
globs:
- "apps/docs/**"
alwaysApply: false
---

# Docs voice (priming)

Before authoring or editing public docs prose, **read the [`docs-voice` skill](../skills/docs-voice/SKILL.md)**.

Voice, competitor framing (store middlewares only), card/header grammar, and anti-sell live in the skill — not duplicated here.

Product north-star: [`product-tenets`](../skills/product-tenets/SKILL.md).
2 changes: 1 addition & 1 deletion .agents/skills/agents-tier-system/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Always-on priming: [`.agents/rules/agents-tier-system.md`](../../rules/agents-ti
| **Tier 3** | `alwaysApply: false`, no `globs:` — intent via `description` |
| **Skills** | `ls .agents/skills` — runtime discovery via descriptions |

**Pairing examples in this repo:** `architecture-priming` ↔ `improve-codebase-architecture`; `docs-governance-priming` ↔ `docs-governance` + `docs-lifecycle-sweep`; `agents-tier-system` rule + skill; `authoring-discipline` rule + PROSE; `verify-after-each-step` rule + skill.
**Pairing examples in this repo:** `architecture-priming` ↔ `improve-codebase-architecture`; `docs-governance-priming` ↔ `docs-governance` + `docs-lifecycle-sweep`; `docs-voice-priming` ↔ `docs-voice`; `agents-tier-system` rule + skill; `authoring-discipline` rule + PROSE; `verify-after-each-step` rule + skill.

**Caution:** avoid stacking broad globs without thin priming bodies.

Expand Down
1 change: 1 addition & 0 deletions .agents/skills/ask-agents/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ Keep grilling + plan authoring in **one window** until issues are filed. Each im
| [`writing-agents-config`](../writing-agents-config/SKILL.md) | Persist repo tier/pairing deltas |
| [`domain-modeling`](../domain-modeling/SKILL.md) | Ubiquitous language inline + batch glossary |
| [`diagnosing-bugs`](../diagnosing-bugs/SKILL.md) | Debug loop for hard bugs |
| [`minimum-diff`](../minimum-diff/SKILL.md) | minimum-diff / why-first / stated-process |

Meta: [`agents-tier-system`](../agents-tier-system/SKILL.md).
6 changes: 6 additions & 0 deletions .agents/skills/docs-governance/LIFECYCLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,9 @@ Preserve cited anchors / rule numbers; if renumbering is unavoidable, update eve
- **Adopted** → lift the decision-of-record into `architecture.md` or a rule/skill; delete the research file unless its comparison framework is reusable.
- **Rejected** → add `Status: Rejected (YYYY-MM-DD) — <one-line reason>` at the top. Keep. The rejection rationale saves the next agent from re-litigating.
- **Open** → stays in `research/` with no status header.

## README surfaces

**The `apps/docs` docs site (built with Blume) is the canonical public documentation** for concepts, API, guides, recipes, adapters, and reference detail. The repo root `README.md` is an **npm/repo landing only**: package name, brand one-liner, install command, optional-peer table (or link), one idiomatic taste snippet, and links to `https://stainless-code.com/persist` — it **must not** restate API tables, when-to-use matrices, lifecycle explanations, or feature lists. Maintainer-facing depth stays in `docs/architecture.md`, `docs/glossary.md`, and the docs site `/reference/*`. On API changes, update the docs site first (`update-docs`); the root README changes only when install/peers/package name change.

PR checklist: docs site updated for behavior/API; README touched only for install/taste/links. Label the PR **`docs`** when it changes `apps/docs/**` (or site-visible root README branding) — merge then deploys `/persist` via `.github/workflows/deploy-docs.yml` (also `release` / `workflow_dispatch`). Not GitHub's default `documentation` label.
9 changes: 3 additions & 6 deletions .agents/skills/docs-governance/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ Repo-wide Tier B surface (cross-cutting reference + lifecycle substrate). This i

## Quick rules

1. **Five lifecycle types** — Reference (`architecture.md`, `roadmap.md`), Roadmap (`roadmap.md`), Plan (`plans/<topic>.md`), Audit (`audits/<topic>.md`), Research (`research/<tool>.md`). New content folds into one of these; no new top-level types.
2. **Existence test** — a doc earns its place if source cites it, it carries durable policy unavailable elsewhere, it tracks open work, or it carries unique historical context. Otherwise fold + delete.
3. **Plans are deleted + lifted when work ships** — durable bits move to `architecture.md` / `roadmap.md` / a rule; the plan file dies. No "slim & keep in plans/" state.
4. **`.gitkeep`** in each lifecycle folder so it stays discoverable when empty.
5. **Anti-bloat** — don't add a rule until there's content that needs it. Density (cut what code already shows) per [`authoring-discipline`](../../rules/authoring-discipline.md); lifecycle stays in [LIFECYCLE.md](./LIFECYCLE.md).
6. **Provenance** — `docs/README.md` cites this skill in its opening; per-surface docs link, never restate the spine.
Full blueprint: [LIFECYCLE.md](./LIFECYCLE.md) — spine (§1–6), README surfaces (`apps/docs` canonical; root README = npm landing; **`docs` label** → FTP `/persist`), Closing states.

Public site sync: [`update-docs`](../update-docs/SKILL.md). Voice: [`docs-voice`](../docs-voice/SKILL.md).

## Reference

Expand Down
84 changes: 84 additions & 0 deletions .agents/skills/docs-voice/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
name: docs-voice
description: Voice, tone, and format for the public Persist docs (`apps/docs`, built with Blume). Use when authoring or editing apps/docs prose — landing, guides, concepts, recipes, adapters, reference — or deciding headline grammar, benefit framing, competitor framing, or anti-sell wording.
---

# Docs voice — Persist docs (`apps/docs`, built with Blume)

Keep landing, guides, concepts, recipes, adapters, and reference reading like one voice.

## Voice in one line

Senior-dev to senior-dev: concrete, API-literate, dry, honest about scope. No
hype. The differentiators are radical honesty (say what's planned / diverges /
was rejected) and the "when **not** to use it" anti-sell — keep both.

## Do

- **Lead with the pain, then the mechanism.** "Async IndexedDB hydrates after
first paint…" → then "`toHydrationSignal` + `useHydrated` gates the tree."
- **Concrete before abstract.** Name localStorage / IndexedDB / zustand /
TanStack Store before the coinage "seam" / `PersistableSource`.
- **Section headers by page type.** Marketing = period-terminated benefit
sentence ("One middleware, any store."); guides = action verb ("Gate UI
until hydrated"); reference = precise noun; concepts = model noun +
consequence.
- **Card titles = the outcome; card bodies = the API.**
- **One idea per sentence in leads.** Short claim first, then expand.
- **State experimental / pre-1.0 status once per surface, one wording** (see
Canonical patterns).
- **Sidebar icons: all-or-none per sibling list.** Blume does not reserve an
icon column — sparse `sidebar.icon` jaggeds labels. Guides, Concepts,
Recipes, Reference leaves: none unless every peer has a natural glyph.
Section `meta.ts` icons and tab icons stay.
- **Adapter / listing order:** core → backends → codecs → sources → frameworks
→ transport. Within sources: tanstack-store → zustand → jotai → valtio →
mobx → custom. Within frameworks: react → preact → solid → angular → vue →
svelte (runes → store).

## Don't

- Don't open a page with a 60+ word sentence.
- Don't restate the frontmatter `description` in the first body sentence — the
docs site renders `description` as the page subtitle, so an echoing opener
duplicates content. Open with a concrete scenario/pain instead.
- Don't title cards with bare feature nouns ("Cross-tab") when the outcome is
the hook ("Sync tabs without a custom `storage` listener").
- Don't manufacture social proof, download counts, "trusted by", or maturity
adjectives ("production-grade", "battle-tested", "world-class") at pre-1.0 —
live examples, source, and the changelog are the proof.
- Don't claim Persist owns UI, focus, or a11y — consumers own rendering; Persist
owns the persistence + hydration lifecycle.
- Don't hype ("blazing-fast", "revolutionary").
- Don't treat query-cache persisters as competitors — peers are **store**
persist middlewares (zustand / redux / pinia). TanStack Store is an
_integration_, not a rival.
- Don't invent Lucide icons for prose nav leaves to "fill out" a section —
strip to none instead of decorating half the list.

## Canonical patterns (use verbatim)

- **Experimental disclaimer** (banner / pill / callout / stability page):
"Experimental — the API may change between minor releases. Pin your version."
- **Pre-1.0 semver:** breaking changes are expected and ship in **minor
releases** (`0.1` → `0.2`), **not majors**.
- **Brand one-liner** (memorable beat, not hype): "Any store, any storage, one
middleware — no flash."
- **Competitor set:** zustand-persist, redux-persist, pinia-persist (and
hand-rolled store persistence). Not TanStack Query persist-client.

## Product tenets

Decisions and messaging should align with [`product-tenets`](../product-tenets/SKILL.md).

## Verify

`content/**` MDX is excluded from oxfmt; `.astro` is not oxfmt-managed. Build
green before commit ([`verify-after-each-step`](../../rules/verify-after-each-step.md)).
Scheduled drift sync: [`update-docs`](../update-docs/SKILL.md).

## Reference

- Priming: [`docs-voice-priming`](../../rules/docs-voice-priming.md)
- Tenets: [`product-tenets`](../product-tenets/SKILL.md)
- Lifecycle / README surfaces: [`docs-governance`](../docs-governance/SKILL.md)
27 changes: 27 additions & 0 deletions .agents/skills/minimum-diff/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: minimum-diff
description: minimum-diff — change only what was requested; recommend before implementing when asked.
disable-model-invocation: true
---

# minimum-diff

All **reference**. Apply every default below for the rest of the turn (or until the user widens scope).

### minimum-diff

Change only what was requested. No adjacent redesign, restyle, or opportunistic cleanup unless asked.

**Done when:** every edited path maps to an explicit request.

### why-first

When the user asks for a recommendation, trade-off, or rationale before implementation — answer first. Do not edit until they confirm.

**Done when:** the recommendation landed before code changes (unless they already authorized implementation).

### stated-process

When the user names a rule or skill that covers the task, follow it. Do not invent a parallel workflow.

**Done when:** the named process was loaded and used; freestyle only where it is silent.
51 changes: 51 additions & 0 deletions .agents/skills/product-tenets/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: product-tenets
description: The product north-star — four tenets (open & agnostic, composable primitives, production-grade, predictable & type-safe) distilled from TanStack's ethos/tenets. Use when making a design, API, or architecture decision, evaluating a trade-off, justifying a feature, or writing/reviewing a docs/plans entry.
---

# Product tenets (north-star)

Distilled from [TanStack's ethos](https://tanstack.com/ethos) and [product tenets](https://tanstack.com/tenets) — a great inspiration whose work we respect and learn from. These four tenets are the design north-star for `@stainless-code/persist`; reach for them whenever a decision needs justifying. Adopted and adapted to a single-package, zero-dep-core, seam-layered persistence middleware.

## 1. Open, independent, technology-agnostic

A store-agnostic core; integrations layered on top as optional adapters — never the foundation. Swapping a store library, storage backend, or serializer is a subpath swap, not a rewrite; framework-specific hydration lives in `./frameworks/*`.

- Rules out: store-biased APIs or peer deps in `src/core/` (the zero-dep gate); "all-in on zustand/TanStack Store" assumptions; lock-in that forces a rewrite when the app changes stores.
- Persist shape: one package, subpath exports per seam (backends / codecs / sources / frameworks / transport), optional peers, structural `PersistableSource`.

## 2. Composable, platform-aligned primitives

Focused, composable building blocks that embrace the web platform rather than hiding it. Adoptable one piece at a time — no rewrites, no hard coupling. Escape hatches by design: always possible to drop down a level (`persistSource` + hand-rolled `StateStorage` / `StorageCodec`).

- Rules out: designs requiring full rewrites or "all-in" commitments; heavy global singletons; abstractions that hide `localStorage` / IndexedDB / WebCrypto without escape routes.
- Persist shape: three seams — backend (`StateStorage`), codec (`StorageCodec`), source (`PersistableSource`); `createStorage(backend, codec)` composition; wrappers (`encrypted`, `compressed`) stack; `PersistRegistry` is opt-in clear-all, not required.

## 3. Pragmatic, production-grade quality

Designed around real-world workloads, edge cases, and long-lived apps — not happy-path demos. Features are not done until we'd run them in our own revenue-critical apps. Performance and reliability are requirements, not nice-to-haves.

- Rules out: demo-only features; magic that's impossible to debug; changes that optimize for benchmarks over real-world reliability (quota, multi-tab, schema evolution, hydrate flash).
- Persist shape: first-class `HydrationSignal`; versioned `migrate`; `crossTab` + `onCrossTabRemove`; `retryWrite` with write-generation guard; `throttleMs` / `maxAge` / `buster`; `onError` with phase.

## 4. Predictable, explicit, type-safe behavior

Minimal magic, maximum clarity. State, side effects, and data flow understandable from code, not hidden behavior. Type safety guides correct use without drowning users in generics. Evolve carefully with clear migration paths.

- Rules out: hidden global state or surprising side effects; API churn without migration docs; type signatures technically correct but unusable in practice.
- Persist shape: explicit options bag; structural options (`registry`, `crossTab`, …) fixed at create time; SSR policy documented (`hydrated = true` on server); pre-1.0 — prefer the cleanest correct design, document breaks in minors.

## Using the tenets

When a proposal conflicts with a tenet, explicitly address why and how the conflict is justified (a `docs/plans/` entry for new surface, inline for a line-level change). Maintainers use these as a PR checklist; partners may not bias core toward a store or framework.

## Competitor framing (docs)

Peers for comparison / migration are **store persist middlewares** (zustand-persist, redux-persist, pinia-persist). Query-cache persisters are a different problem space — do not treat them as Persist competitors.

## Reference

- [TanStack ethos](https://tanstack.com/ethos) · [TanStack product tenets](https://tanstack.com/tenets) — inspiration, with respect.
- [`architecture-priming`](../../rules/architecture-priming.md) — STOP signals for structurally significant changes.
- [`improve-codebase-architecture`](../improve-codebase-architecture/SKILL.md) · [`docs/architecture.md`](../../../docs/architecture.md)
- [`docs-voice`](../docs-voice/SKILL.md) — public docs tone.
Loading
Loading