-
-
Notifications
You must be signed in to change notification settings - Fork 140
docs: add Cursor rules, syntax cheat sheet, and AI agent context #1606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
WolfieLeader
wants to merge
10
commits into
arktypeio:main
Choose a base branch
from
WolfieLeader:docs/improve-llm-knowledge
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7c2711e
docs: add syntax cheat sheet page
WolfieLeader e64c188
docs: add Cursor rules file for AI/LLM usage
WolfieLeader 839de74
fix: remove number.finite reference (not yet on main)
WolfieLeader 186f695
docs: add CLAUDE.md and AGENTS.md for AI agent context
WolfieLeader 146db7c
fix: move default value example inside object context
WolfieLeader 93521ba
fix: defaults make keys implicitly optional, remove redundant ?
WolfieLeader f308dcd
fix: define Item type to resolve MyType reference in code block
WolfieLeader 3e788c8
fix: make error handling code block self-contained
WolfieLeader 8ce2314
style: fix prettier formatting in CLAUDE.md and cheat-sheet.mdx
WolfieLeader 8805e91
fix: address review feedback on AI context files
WolfieLeader File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| --- | ||
| description: When working with ArkType for schema validation. Covers common patterns, pitfalls, and idiomatic usage. | ||
| globs: "**/*.ts" | ||
| alwaysApply: false | ||
| --- | ||
|
|
||
| # ArkType Usage Guidelines | ||
|
|
||
| ## Optional Keys | ||
|
|
||
| ```ts | ||
| // ❌ WRONG | ||
| type({ name: "string | undefined" }) | ||
|
|
||
| // ✅ CORRECT — append ? to the key | ||
| type({ "name?": "string" }) | ||
| ``` | ||
|
|
||
| ## Schema References | ||
|
|
||
| **In objects** — pass schemas directly: | ||
| ```ts | ||
| const Inner = type({ foo: "string" }) | ||
| const Outer = type({ inner: Inner }) | ||
| ``` | ||
|
|
||
| **In records** — use index signature syntax: | ||
| ```ts | ||
| // ❌ WRONG: "Record<string, Schema>" | ||
| // ✅ CORRECT: | ||
| type({ "[string]": Schema }) | ||
| ``` | ||
|
|
||
| **In arrays** — use `.array()`: | ||
| ```ts | ||
| // ❌ WRONG: type([Schema]) — creates a 1-element tuple | ||
| // ✅ CORRECT: | ||
| Schema.array() | ||
| ``` | ||
|
|
||
| ## Type Inference | ||
|
|
||
| ```ts | ||
| type User = typeof UserSchema.infer | ||
| ``` | ||
|
|
||
| ## Type Declaration | ||
|
|
||
| Match a schema to an existing TypeScript type: | ||
| ```ts | ||
| const Schema = type.declare<MyType>().type({ | ||
| items: type.string.array().readonly() // readonly string[] | ||
| }) | ||
| ``` | ||
|
|
||
| ## Error Handling | ||
|
|
||
| ```ts | ||
| const out = Schema(data) | ||
| if (out instanceof type.errors) { | ||
| console.error(out.summary) | ||
| } | ||
| ``` | ||
|
|
||
| ## Syntax Kinds | ||
|
|
||
| Three equivalent ways to define types: | ||
|
|
||
| ```ts | ||
| // string expression | ||
| type("string | number") | ||
|
|
||
| // tuple expression | ||
| type(["string", "|", "number"]) | ||
|
|
||
| // chained | ||
| type("string").or("number") | ||
| ``` | ||
|
|
||
| ## Keywords Pattern | ||
|
|
||
| Keywords follow `typescriptType.constraint.subconstraint`: | ||
|
|
||
| - `string.email`, `string.uuid`, `string.url` | ||
| - `number.integer`, `number.safe`, `number.epoch` | ||
| - `string.trim`, `string.json.parse`, `string.date.parse` (morphs) | ||
|
|
||
| ## Operators | ||
|
|
||
| ```ts | ||
| type("string | number") // union | ||
| type("string & /@pattern/") // intersection | ||
| type("number > 0") // exclusive min | ||
| type("number >= 0") // inclusive min | ||
| type("string <= 255") // max length | ||
| type({ name: "string = 'default'" }) // default value | ||
| ``` | ||
|
|
||
| ## Morphs | ||
|
|
||
| ```ts | ||
| type("string").to("number.integer") // validated transform | ||
| type("string").pipe(s => s.trim()) // custom transform | ||
| type("string.json.parse") // built-in parse morph | ||
| ``` | ||
|
|
||
| ## Common Mistakes | ||
|
|
||
| 1. `type([X])` creates a tuple, not an array — use `X.array()` | ||
| 2. `"string | undefined"` for optional — use `"key?": "string"` | ||
| 3. `"Record<string, T>"` — use `type({ "[string]": T })` | ||
| 4. Re-validating after `type()` passes — trust ArkType's output | ||
| 5. `typeof Schema.t` — use `typeof Schema.infer` for output type |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| CLAUDE.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # ArkType — Agent Context | ||
|
|
||
| ArkType is TypeScript's 1:1 validator, optimized from editor to runtime. It parses TypeScript-like string syntax at runtime — this is unique among validation libraries. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```bash | ||
| pnpm i && pnpm build # install and build all packages | ||
| pnpm prChecks # lint + build + test (run before PRs) | ||
| pnpm testTyped --skipTypes # run tests without type checking | ||
| ``` | ||
|
|
||
| ## Monorepo Structure | ||
|
|
||
| - `ark/type/` — main validation library (`arktype` on npm) | ||
| - `ark/schema/` — schema layer (constraint nodes, refinements, scopes) | ||
| - `ark/util/` — shared utilities | ||
| - `ark/docs/` — documentation site (Fumadocs/Next.js) | ||
| - `ark/json-schema/` — JSON Schema conversion | ||
| - `ark/regex/` — ArkRegex type-safe regex | ||
| - `ark/attest/` — custom assertion/test library | ||
| - `ark/fast-check/` — property testing integration | ||
|
|
||
| ## Key Patterns | ||
|
|
||
| **String keywords** follow `typescriptType.constraint.subconstraint`: | ||
|
|
||
| - `string.email`, `string.uuid`, `string.url`, `string.hex` | ||
| - `number.integer`, `number.safe`, `number.epoch` | ||
| - Morphs: `string.trim`, `string.json.parse`, `string.date.parse` | ||
|
|
||
| **Adding a regex string validator:** | ||
|
|
||
| ```ts | ||
| const myValidator = regexStringNode(/^pattern$/, "description") | ||
| ``` | ||
|
|
||
| Register in `Scope.module()` in `ark/type/keywords/string.ts` and add to the namespace `$` type. | ||
|
|
||
| **Adding a number keyword:** | ||
| Use `rootSchema()` with `domain`, `min`/`max`, or `predicate` constraints. See `number.safe` in `ark/type/keywords/number.ts`. | ||
|
|
||
| ## Code Style | ||
|
|
||
| - Tabs, no semicolons, no trailing commas (`prettier` enforced) | ||
| - `experimentalTernaries: true` — `?` at end of line, `:` on next line | ||
| - `arrowParens: "avoid"` — `x => x` not `(x) => x` | ||
| - Tests use `attest` (custom lib) with `.snap()` for snapshots | ||
|
|
||
| ## ArkType Syntax Cheat Sheet | ||
|
|
||
| ```ts | ||
| // optional keys — append ? to the key name | ||
| type({ "name?": "string" }) | ||
|
|
||
| // arrays — use .array(), NOT type([Schema]) | ||
| Schema.array() | ||
|
|
||
| // records — use index signature syntax | ||
| type({ "[string]": ValueSchema }) | ||
|
|
||
| // type inference | ||
| type User = typeof UserSchema.infer | ||
|
|
||
| // error handling | ||
| const out = Schema(data) | ||
| if (out instanceof type.errors) { | ||
| console.error(out.summary) | ||
| } | ||
|
|
||
| // three syntax kinds (equivalent): | ||
| type("string | number") // string expression | ||
| type(["string", "|", "number"]) // tuple expression | ||
| type("string").or("number") // chained | ||
| ``` | ||
|
|
||
| ## Common Gotchas | ||
|
|
||
| - `type([X])` creates a 1-element **tuple**, not an array — use `X.array()` | ||
| - `"string | undefined"` for optional — use `"key?": "string"` instead | ||
| - `"Record<string, T>"` doesn't work — use `type({ "[string]": T })` | ||
| - `safeParse()` doesn't exist — call the type directly: `const out = Schema(data)` | ||
| - `regexStringNode()` patterns must be anchored with `^`/`$` | ||
|
|
||
| <!-- Keep in sync: .cursor/rules/arktype.mdc, ark/docs/content/docs/cheat-sheet.mdx --> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| --- | ||
| title: Cheat Sheet | ||
| --- | ||
|
|
||
| A quick reference for ArkType's most common patterns. For full docs, explore the sidebar. | ||
|
|
||
| ## Syntax Kinds | ||
|
|
||
| ArkType offers three ways to define the same type. Use whichever fits your context. | ||
|
|
||
| ```ts | ||
| import { type } from "arktype" | ||
|
|
||
| // string expression — most concise | ||
| const StringSyntax = type("string | number") | ||
|
|
||
| // tuple expression — embed non-string operands | ||
| const TupleSyntax = type(["string", "|", "number"]) | ||
|
|
||
| // chained — compose existing types | ||
| const Chained = type("string").or("number") | ||
| ``` | ||
|
|
||
| ## Keywords | ||
|
|
||
| Keywords follow a `typescriptType.constraint.subconstraint` pattern: | ||
|
|
||
| ```ts | ||
| // string keywords | ||
| type("string.email") // email format | ||
| type("string.uuid") // UUID format | ||
| type("string.url") // parsable URL | ||
| type("string.trim") // morph: trims whitespace | ||
| type("string.json.parse") // morph: string → parsed JSON | ||
| type("string.date.parse") // morph: string → Date | ||
|
|
||
| // number keywords | ||
| type("number.integer") // whole numbers | ||
| type("number.safe") // within safe integer range | ||
| type("number.epoch") // valid Unix timestamp | ||
| ``` | ||
|
|
||
| ## Operators | ||
|
|
||
| ```ts | ||
| type("string | number") // union | ||
| type("string & /@foo/") // intersection | ||
| type("number > 0") // exclusive min | ||
| type("number >= 0") // inclusive min | ||
| type("string <= 255") // max length | ||
|
|
||
| // defaults — valid inside objects (key becomes implicitly optional) | ||
| type({ email: "string.email = 'n/a'" }) | ||
| ``` | ||
|
|
||
| ## Objects | ||
|
|
||
| ```ts | ||
| const User = type({ | ||
| name: "string", | ||
| "email?": "string.email", // optional key — use '?' suffix in the key | ||
| age: "number >= 0 = 0" // default value — implicitly optional | ||
| }) | ||
|
|
||
| // index signatures (Record types) | ||
| const Env = type({ | ||
| "[string]": "string" // Record<string, string> | ||
| }) | ||
|
|
||
| // strip undeclared keys | ||
| const Strict = User.onUndeclaredKey("delete") | ||
| ``` | ||
|
|
||
| ## Arrays and Tuples | ||
|
|
||
| ```ts | ||
| const Strings = type("string[]") // string expression | ||
| const Numbers = type.number.array() // chained | ||
|
|
||
| // tuples — fixed length and positional types | ||
| const Pair = type(["string", "number"]) | ||
|
|
||
| // GOTCHA: type([X]) is a 1-element tuple, NOT an array | ||
| const Item = type({ id: "string" }) | ||
| const Wrong = type([Item]) // tuple of exactly [Item] | ||
| const Right = Item.array() // Item[] | ||
|
|
||
| // readonly | ||
| const Ids = type("string[]").readonly() // readonly string[] | ||
| ``` | ||
|
|
||
| ## Composition | ||
|
|
||
| ```ts | ||
| const Device = type({ | ||
| platform: "'android' | 'ios'", | ||
| "version?": "string" | ||
| }) | ||
|
|
||
| // reference in another type — just pass it directly | ||
| const User = type({ | ||
| name: "string", | ||
| device: Device | ||
| }) | ||
|
|
||
| // fluent composition | ||
| const Admin = User.and({ role: "'admin'" }) | ||
| const Guest = type({ name: "string" }).or({ token: "string" }) | ||
| ``` | ||
|
|
||
| ## Morphs and Pipes | ||
|
|
||
| ```ts | ||
| // .to() — validated input → validated output | ||
| const ParsedInt = type("string").to("number.integer") | ||
|
|
||
| // .pipe() — validated input → transform function | ||
| const ToUpper = type("string").pipe(s => s.toUpperCase()) | ||
|
|
||
| // built-in parse morphs | ||
| const ParseDate = type("string.date.parse") // string → Date | ||
| const ParseJson = type("string.json.parse") // string → object | ||
| const Trimmed = type("string.trim") // string → trimmed string | ||
| ``` | ||
|
|
||
| ## Type Inference | ||
|
|
||
| ```ts | ||
| const User = type({ | ||
| name: "string", | ||
| "age?": "number" | ||
| }) | ||
|
|
||
| // extract the TypeScript type | ||
| type User = typeof User.infer | ||
| // { name: string; age?: number } | ||
| ``` | ||
|
|
||
| ## Error Handling | ||
|
|
||
| ```ts | ||
| const User = type({ | ||
| name: "string", | ||
| "age?": "number" | ||
| }) | ||
|
|
||
| const out = User({ name: "Alan", age: "not a number" }) | ||
|
|
||
| if (out instanceof type.errors) { | ||
| // ArkErrors — array-like with .summary | ||
| console.error(out.summary) | ||
| } else { | ||
| // out is typed as { name: string; age?: number } | ||
| console.log(out.name) | ||
| } | ||
| ``` | ||
|
|
||
| ## Common Gotchas | ||
|
|
||
| | Mistake | Fix | | ||
| | ------------------------------------------ | ----------------------------------------------------------- | | ||
| | `name: "string \| undefined"` for optional | Use `"name?": "string"` — append `?` to the **key** | | ||
| | `type([Schema])` for arrays | Use `Schema.array()` — brackets create tuples | | ||
| | `"Record<string, T>"` for records | Use `type({ "[string]": T })` — index signature syntax | | ||
| | Manually re-validating after `type()` | Trust ArkType's output — it already validated the structure | | ||
| | `type User = typeof Schema.t` | Use `typeof Schema.infer` for the output type | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| { | ||
| "pages": [ | ||
| "intro", | ||
| "cheat-sheet", | ||
| "primitives", | ||
| "objects", | ||
| "keywords", | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.