About atscript
atscript is a language-agnostic schema language and toolchain for defining types, metadata, and validation in `.as` files. Its TypeScript compiler generates declarations and runtime metadata for validation, JSON Schema, serialization, and related consumers.
Key features
- 01Single-source `.as` definitions
- 02TypeScript declarations and runtime code generation
- 03Metadata and validation support
- 04JSON Schema and serialization helpers
- 05Plugin-based annotation namespaces
- 06CLI and editor integrations
Use cases
- 01Define shared types and metadata
- 02Generate TypeScript declarations from `.as` files
- 03Validate data and produce JSON Schema
- 04Integrate `.as` models into build workflows
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ moostjs/ atscript --skill atscriptAfter installing, type/atscriptin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/annotations.mdas-syntax.mdasc-cli.mdcodegen.mdconfig.mdgetting-started.mdmoost-validator.mdplugin-development.mdprimitives.mdruntime.mdunplugin.mdvalidation.mdvscode.mdDetails
From the project READMEatscript
.as = single source of truth for types + metadata + validation. @atscript/typescript compiles .as → .d.ts (types) + .js (runtime metadata). Consumers use those for validation, JSON Schema, serialization, ORM mapping.
Language-agnostic. Core ships @meta.*, @expect.*, @emit.*; @db.*, @ui.*, and custom namespaces come from plugins.
Quick start
npm install @atscript/typescript @atscript/core
atscript.config.{ts,mts,cts,js,mjs,cjs} at project root:
import { defineConfig } from '@atscript/core'
import ts from '@atscript/typescript'
export default defineConfig({
rootDir: './src',
plugins: [ts()],
})
Build:
npx asc # emits .d.ts (default) + project-wide atscript.d.ts
npx asc -f js # emits runtime .js metadata
Full walkthrough with a first .as file, consume snippet, and troubleshooting → getting-started.md.
Key imports
// Config
import { defineConfig, AnnotationSpec } from '@atscript/core'
import type { TAtscriptPlugin, TAtscriptConfig } from '@atscript/core'
// Plugin factory (build-time only)
import ts from '@atscript/typescript'
// Runtime helpers (used by generated .as.js — also available to consumers)
import {
defineAnnotatedType, // fluent builder (in generated code)
forAnnotatedType, // kind-dispatched walker
Validator, ValidatorError,
buildJsonSchema, fromJsonSchema, mergeJsonSchemas, detectDiscriminator,
serializeAnnotatedType, deserializeAnnotatedType, SERIALIZE_VERSION,
isAnnotatedType, isAnnotatedTypeOfPrimitive,
} from '@atscript/typescript/utils'
import type { TAtscriptAnnotatedType, TValidatorPlugin } from '@atscript/typescript/utils'
// Test fixtures (compile .as at test-time, inject tsPlugin automatically)
import { prepareFixtures } from '@atscript/typescript/test-utils'
// Moost HTTP integration
import { coercionPipe, validatorPipe, validationErrorTransform } from '@atscript/moost-validator'
// Bundler integration (pick one)
import atscript from 'unplugin-atscript/vite' // or /rollup /rolldown /webpack /esbuild /rspack /farm
Invariants
@meta.idtakes no arguments. Multiple@meta.idon different props = composite PK. Never@meta.id(...).- Generated files (
*.as.d.ts,*.as.js,atscript.d.ts) are never hand-edited. Fix the.assource or plugin. Regenerate withnpx asc -f dts. - Core ships
@meta.*,@expect.*,@emit.*only. All other namespaces come from plugins. ascwithout-fruns every plugin's default output (TS plugin emits.d.ts). Pass-f jsfor runtime.js(or letunplugin-atscriptproduce it at bundle time).@atscript/typescript/utilsis the runtime entry;@atscript/typescriptdefault export istsPlugin()(build-time factory).- Never
import typea compiled.asartifact..asexports are classes — value AND type in one name — consumed at runtime (.validator(),.metadata, decorators, DI by param type viadesign:paramtypes). A type-only import elides the value: decorator metadata emitsObjectand validation/DI/form binding break silently. Keep lint rules that force type-only imports (typescript/consistent-type-importsand equivalents) off in projects importing.asfiles — the create-moost preset and ecosystem repos already disable it.
Dependency chain
@atscript/core parser, AST, plugin system, diagnostics
└─ @atscript/typescript codegen + runtime + asc CLI
├─ @atscript/moost-validator Moost pipe + error transform
└─ unplugin-atscript Vite/Rollup/Rolldown/Webpack/esbuild/Rspack/Farm
└─ @atscript/vscode LSP, syntax, completions, go-to-def
DB layer (@atscript/db, db-sqlite, db-mongo, db-mysql, moost-db, @db.*, schema sync, relations, views): separate repo at https://db.atscript.dev.
UI layer (@atscript/ui, vue-form, vue-table, Moost workflow, @ui.*): separate repo.
Companion skills:
npx skills add moostjs/atscript # this skill (core/typescript/unplugin/vscode/moost-validator)
npx skills add moostjs/atscript-db # DB layer
npx skills add moostjs/atscript-ui # UI layer
References — load only what's needed
| Domain | File | When |
|---|---|---|
| First contact | getting-started.md | Install, first .as, first codegen run, consume snippet, troubleshooting |
.as syntax | as-syntax.md | interface/type, unions, intersections, tuples, arrays, imports, pattern properties, annotate blocks |
| Annotations | annotations.md | @meta.*, @expect.*, merge, custom AnnotationSpec, query / expr / order args (backtick expressions, arithmetic, orderings, operators inside parentheses, "Expected operator after field reference"), editor hooks on args (fieldScope, refFilter — completion/hover/F12 inside args) |
| Primitives | primitives.md | Built-ins, semantic extensions, decimal, phantom, extending via config |
| Config | config.md | atscript.config.*, defineConfig, entries/globs, plugin wiring, output, models (packaged models for db sync, models: () => import(...)) |
asc CLI | asc-cli.md | asc, -f, -c, --noEmit, --skipDiag, scripts, "Nothing emitted" / errors block the emit, atomic writes, db sync flags (--check, --format), complete-inventory rule ("Could not load N compiled model module(s)", ERR_MODULE_NOT_FOUND, nested .as imports) + pointer |
| Codegen | codegen.md | .as → .d.ts/.js, atscript.d.ts global AtscriptMetadata |
| Runtime | runtime.md | defineAnnotatedType, TAtscriptAnnotatedType, forAnnotatedType, serialize, refDepth |
| Validation | validation.md | Validator, ValidatorError, coerceForType, JSON Schema helpers, plugins |
| Build integration | unplugin.md | Vite/Rollup/Rolldown/Webpack/esbuild/Rspack/Farm, HMR, strict, root (config discovered from the wrong cwd, pnpm -C, unknown @db.*/@ui.* annotations), optimizeDeps prebundling of @atscript/typescript/utils ("optimized dependencies changed. reloading"), stale .as import after moving/retyping a model (dev server keeps the old field type, "requires string" on reload while asc/tsc pass, watchChange cache invalidation), dts bundling of .as re-exports (tsdown/rolldown-plugin-dts) |
| Moost integration | moost-validator.md | Moost pipes (validation + param/query coercion), error transform |
| VSCode | vscode.md | Extension, LSP features, config autodiscovery |
| Plugin authoring | plugin-development.md | TAtscriptPlugin, AnnotationSpec, render/buildEnd |
Full docs: https://atscript.dev.