@nifrajs/skills 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "nifra",
3
+ "description": "Skills for building and verifying Nifra apps: contract-first APIs, full-stack SSR on five UI libraries, and the check/assure/capabilities gates. Prefers Nifra's live MCP server over model recall.",
4
+ "version": "2.11.0",
5
+ "homepage": "https://nifra.dev/docs/agents",
6
+ "repository": "https://github.com/nifrajs/nifra",
7
+ "license": "MIT",
8
+ "keywords": ["nifra", "typescript", "bun", "web-framework", "mcp"]
9
+ }
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @nifrajs/skills
2
+
3
+ Portable agent skills for [Nifra](../../README.md) - one `SKILL.md` bundle, published to every agent
4
+ surface that reads a `skills/` directory.
5
+
6
+ A skill is loaded on demand: the agent sees only each skill's name and description until it decides
7
+ one applies, then reads the body. That keeps Nifra's conventions out of the context window until they
8
+ matter.
9
+
10
+ ```
11
+ skills/
12
+ nifra/SKILL.md entry point - MCP-first rule, the core loop, the non-negotiables
13
+ nifra-api/SKILL.md typed routes, schemas, middleware, WebSockets, the never-throwing client
14
+ nifra-web/SKILL.md file routing, loaders/actions, SSR, islands, the client/server boundary
15
+ nifra-verify/SKILL.md check, assure, capabilities, manifest diff, the verification ladder
16
+ ```
17
+
18
+ ## Install
19
+
20
+ **Pi**
21
+
22
+ ```sh
23
+ pi install npm:@nifrajs/skills
24
+ ```
25
+
26
+ **Claude Code**
27
+
28
+ ```sh
29
+ /plugin marketplace add nifrajs/nifra
30
+ /plugin install nifra@nifra
31
+ ```
32
+
33
+ **Anything that reads a skills directory** (Cursor, `.agents/skills`, a project `.pi/skills`)
34
+
35
+ ```sh
36
+ bun add -d @nifrajs/skills
37
+ cp -R node_modules/@nifrajs/skills/skills/* .agents/skills/
38
+ ```
39
+
40
+ ## These skills are deliberately thin
41
+
42
+ They teach shape and rules, not signatures. Signatures come from the MCP server, which is typechecked
43
+ against the version installed in the project being edited:
44
+
45
+ ```sh
46
+ bunx @nifrajs/cli init-agents # register the MCP server in an existing app
47
+ ```
48
+
49
+ Not in a Nifra project? The docs tools are hosted at `https://mcp.nifra.dev`.
50
+
51
+ That split is the anti-drift design: a skill that restated the API would rot on the next release,
52
+ while a skill that says "ask `nifra_types`" stays correct. Keep it that way when editing these files -
53
+ if you find yourself pasting a signature in, reach for a tool reference instead.
54
+
55
+ ## For AI agents
56
+
57
+ Start with [`LLM.md`](./LLM.md) - this package's contract card, one cheap read instead of the whole
58
+ corpus. For the wider framework: the repo's [`AGENTS.md`](../../AGENTS.md) is the copy-paste quick
59
+ reference, and [`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run
60
+ `nifra check` as the done-gate, or `nifra mcp` to give the agent live project tools.
61
+
62
+ MIT licensed.
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@nifrajs/skills",
3
+ "version": "2.12.0",
4
+ "description": "Agent skills for nifra - portable SKILL.md bundles that teach a coding agent Nifra's contracts, boundaries, and CI gates, and point it at the live MCP server instead of stale recall.",
5
+ "keywords": [
6
+ "pi-package",
7
+ "nifra",
8
+ "bun",
9
+ "typescript",
10
+ "ai-agent",
11
+ "agent-skills",
12
+ "skills",
13
+ "claude-code",
14
+ "cursor",
15
+ "mcp",
16
+ "agents-md",
17
+ "web-framework"
18
+ ],
19
+ "type": "module",
20
+ "files": [
21
+ "skills",
22
+ ".claude-plugin"
23
+ ],
24
+ "pi": {
25
+ "skills": [
26
+ "./skills"
27
+ ]
28
+ },
29
+ "sideEffects": false,
30
+ "license": "MIT",
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/nifrajs/nifra.git",
37
+ "directory": "packages/skills"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/nifrajs/nifra/issues"
41
+ },
42
+ "homepage": "https://nifra.dev/docs/agents"
43
+ }
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: nifra
3
+ description: Use when writing, reviewing, or debugging code in a Nifra project (@nifrajs/* packages, `nifra` CLI, server()/defineContract, loaders and actions, file routes under routes/). Explains how to reach Nifra's live MCP tools so signatures come from the installed version instead of memory, and which sibling skill to load for API, full-stack, or verification work.
4
+ metadata:
5
+ homepage: https://nifra.dev
6
+ docs: https://nifra.dev/docs
7
+ ---
8
+
9
+ # Nifra
10
+
11
+ Nifra is a Bun-native, contract-first, framework-agnostic full-stack TypeScript framework. One schema
12
+ drives runtime validation, TypeScript types, the typed client, and OpenAPI. The whole lifecycle is
13
+ `app.fetch(Request): Promise<Response>`, so one app runs on Bun, Node, Deno, Cloudflare Workers, and
14
+ Vercel Edge.
15
+
16
+ ## Rule zero: do not write Nifra from memory
17
+
18
+ Nifra ships a verified MCP server. Its answers are typechecked against the version installed in the
19
+ project you are editing, so they beat recall. Prefer it over guessing an API, and over reading
20
+ `node_modules/@nifrajs/**/*.d.ts`.
21
+
22
+ If the project already has `.mcp.json` or `.cursor/mcp.json`, the server is registered. If not:
23
+
24
+ ```sh
25
+ bunx @nifrajs/cli init-agents # writes .mcp.json, .cursor/mcp.json, AGENTS.md, CLAUDE.md
26
+ ```
27
+
28
+ Not inside a Nifra project (answering a question, comparing frameworks, writing a snippet)? The docs
29
+ tools are hosted at `https://mcp.nifra.dev` - same corpus, no checkout.
30
+
31
+ Tools worth knowing, in the order you usually need them:
32
+
33
+ | Tool | Use it for |
34
+ |---|---|
35
+ | `nifra_context` | This project's live route index, schemas, and conventions. Call first in unfamiliar code. |
36
+ | `nifra_docs` | The prose doc for a concept, pinned to the installed version. |
37
+ | `nifra_example` | A snippet that compiled against this version in CI. Never hand-write what this returns. |
38
+ | `nifra_types` | The exact TypeScript of any `@nifrajs/*` symbol. |
39
+ | `nifra_run` | Execute a real request against the app in-process to check behaviour. |
40
+ | `nifra_check` | The done-gate. See `nifra-verify`. |
41
+ | `nifra_assure` | Per-route security evidence. See `nifra-verify`. |
42
+
43
+ No MCP available at all? Fall back to `https://nifra.dev/llms.txt` (index) or
44
+ `https://nifra.dev/llms-full.txt` (every doc page inlined), and to each package's `LLM.md` contract
45
+ card in `node_modules/@nifrajs/<pkg>/LLM.md`.
46
+
47
+ ## The core loop
48
+
49
+ ```ts
50
+ // server.ts
51
+ import { server } from "@nifrajs/core/server"
52
+ import { t } from "@nifrajs/schema"
53
+
54
+ export const app = server()
55
+ .get("/users/:id", (c) => ({ id: c.params.id }))
56
+ .post("/users", { body: t.object({ name: t.string() }) }, (c) => {
57
+ // c.body is validated and typed - invalid input became a structured 422 before this ran
58
+ return { id: crypto.randomUUID(), name: c.body.name }
59
+ })
60
+ .listen(3000)
61
+ ```
62
+
63
+ ```ts
64
+ // anywhere.ts - inferred from the server, zero codegen
65
+ import { client } from "@nifrajs/client"
66
+ import type { app } from "./server"
67
+
68
+ const api = client<typeof app>("http://localhost:3000")
69
+
70
+ const res = await api.users({ id: "42" }).get()
71
+ if (res.ok) res.data.id // typed from the route
72
+ else res.error // failures are returned, never thrown
73
+ ```
74
+
75
+ Change a route and every caller stops compiling. That property is the point: it is what keeps an
76
+ agent-edited codebase correct.
77
+
78
+ ## Non-negotiables when you edit a Nifra project
79
+
80
+ 1. **Never hand-roll `fetch()` against this app's own API.** Use the typed client. `nifra check`
81
+ fails the build on hand-rolled calls, and it is right to.
82
+ 2. **Validate at the boundary, not in the handler.** Put the schema in the route options so invalid
83
+ input is a `422` before your code runs.
84
+ 3. **Failures are returned, not thrown.** Client results are `{ ok, data } | { ok: false, error }`.
85
+ Do not wrap client calls in try/catch expecting a throw.
86
+ 4. **Server-only code stays out of `routes/`.** A `node:` or native import reaching the client bundle
87
+ is a build error, not a warning.
88
+ 5. **Run the gate before you claim done.** `nifra check` (or the `nifra_check` tool). A failing check
89
+ means the work is not finished.
90
+
91
+ ## Which skill next
92
+
93
+ - Typed JSON APIs, schemas, contracts, middleware, the client -> load `nifra-api`.
94
+ - File routes, loaders, actions, SSR, islands, React/Vue/Solid/Svelte/Preact -> load `nifra-web`.
95
+ - `nifra check`, `nifra assure`, capabilities, the manifest, CI gates -> load `nifra-verify`.
96
+
97
+ ## Starting from scratch
98
+
99
+ ```sh
100
+ bun create nifra my-app # full-stack: pick framework, runtime, DB, auth, CI
101
+ bun create nifra my-app --framework svelte # react | vue | solid | preact | svelte
102
+ bun add @nifrajs/core @nifrajs/schema @nifrajs/client # just a typed API
103
+ ```
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: nifra-api
3
+ description: Use when building or changing a typed JSON API in Nifra - routes with server() or defineContract, request validation with @nifrajs/schema or any Standard Schema library, middleware and plugins, WebSockets, OpenAPI, and consuming the API from the zero-codegen @nifrajs/client. Load after the `nifra` skill.
4
+ metadata:
5
+ docs: https://nifra.dev/docs/api
6
+ ---
7
+
8
+ # Nifra: typed APIs and the typed client
9
+
10
+ Fetch exact signatures with `nifra_types` and compiling snippets with `nifra_example` before writing
11
+ anything non-trivial. This skill is the shape of the thing, not a substitute for either.
12
+
13
+ ## Two ways to declare routes
14
+
15
+ **`server()`** - chainable, inference-first. Reach for this by default.
16
+
17
+ ```ts
18
+ import { server } from "@nifrajs/core/server"
19
+ import { t } from "@nifrajs/schema"
20
+
21
+ export const app = server()
22
+ .get("/notes", () => listNotes())
23
+ .get("/notes/:id", { params: t.object({ id: t.string() }) }, (c) => getNote(c.params.id))
24
+ .post("/notes", { body: t.object({ title: t.string(), body: t.string() }) }, (c) =>
25
+ createNote(c.body),
26
+ )
27
+ ```
28
+
29
+ **`defineContract`** - the same routes as a standalone, versionable artifact when the contract must
30
+ be published, shared across repos, or evolved independently of the handlers. Ask `nifra_docs` for
31
+ the contract page before choosing it; do not reach for it just because a route feels important.
32
+
33
+ ## Validation belongs in the route options
34
+
35
+ `body`, `query`, `params`, `headers`, and `response` all take a schema. Anything that fails becomes a
36
+ structured `422` before your handler runs, so a handler never defensively re-checks its own input.
37
+
38
+ `@nifrajs/schema` (`t`) is TypeBox-backed and gives you JSON Schema and OpenAPI for free. Any
39
+ [Standard Schema](https://standardschema.dev) library works too - Zod and Valibot slot into the same
40
+ option with no adapter.
41
+
42
+ ```ts
43
+ import { z } from "zod"
44
+ app.post("/users", { body: z.object({ email: z.string().email() }) }, (c) => c.body.email)
45
+ ```
46
+
47
+ Typed search params: declare `query` and read `c.query` typed. Do not parse `new URL(c.req.url)` by
48
+ hand.
49
+
50
+ ## The client never throws
51
+
52
+ ```ts
53
+ const res = await api.notes({ id }).get()
54
+ if (!res.ok) return handle(res.error) // transport and HTTP failures both land here
55
+ res.data // typed from the route's return type
56
+ ```
57
+
58
+ Three consequences worth internalising:
59
+
60
+ - No `try`/`catch` around a client call for HTTP or network failure. Only genuinely exceptional code
61
+ throws.
62
+ - The client is browser-safe. It carries the server's *types*, never its code.
63
+ - Changing a route's shape breaks every caller at compile time. That is the feature. Fix the callers;
64
+ do not widen the type to silence `tsc`.
65
+
66
+ ## Middleware
67
+
68
+ `@nifrajs/middleware` ships the production set: `requestId`, `logger`, `etag`, `bearer`, `apiKey`,
69
+ `basicAuth`, `jwt`/`jwks`, `csrf`, `ipRestriction`, `bodyLimit`, `cors`, `securityHeaders`,
70
+ `rateLimit`, `compression`, `cacheControl`, `cache`, `prettyJson`, `timing`, `methodOverride`,
71
+ `trailingSlash`, `language`, `poweredBy`, `combine`, `openapi`, `healthcheck`, `idempotency`.
72
+
73
+ Check that list before writing your own. Hand-rolled CORS, rate limiting, or CSRF is how a project
74
+ acquires a security hole. Custom cross-cutting behaviour goes through `definePlugin` (typed context,
75
+ idempotent registration), not a hand-patched handler wrapper.
76
+
77
+ ## WebSockets
78
+
79
+ `app.ws(path, handler)` registers a typed WebSocket route: upgrade guard, portable socket,
80
+ contract-validated messages, topic pub/sub. Served on Bun, Deno, Node, and Workers. Ask
81
+ `nifra_example` for the current shape; the message-contract generics are easy to get wrong from memory.
82
+
83
+ ## Runtimes
84
+
85
+ The app is `app.fetch(Request): Promise<Response>`. Bun is first-class; Node
86
+ (`@nifrajs/node`), Deno (`@nifrajs/deno`), Workers (`@nifrajs/workers`), Lambda
87
+ (`@nifrajs/aws-lambda`), and Vercel Edge are each one adapter import. Do not fork the app per target.
88
+
89
+ ## Common mistakes
90
+
91
+ | Mistake | Do instead |
92
+ |---|---|
93
+ | `fetch("/api/notes")` inside the same project | `client<typeof app>()`, or `ctx.api` in a loader |
94
+ | `try { await api.x.get() } catch` | Check `res.ok` |
95
+ | Validating in the handler body | Put the schema in the route options |
96
+ | Reading `c.req.headers.get("x-forwarded-for")` for the caller IP | Use the documented request helper; proxy headers are forgeable |
97
+ | Hand-writing an OpenAPI document | `openapi` middleware derives it from the schemas |
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: nifra-verify
3
+ description: Use before declaring Nifra work complete, when a Nifra CI gate fails, or when wiring Nifra checks into CI - `nifra check` drift gate, `nifra assure` route security evidence, `nifra capabilities check` effect provenance, `nifra manifest diff` deploy promotion, `nifra doctor`, the verification ladder, and contract-derived testing with @nifrajs/testing. Load after the `nifra` skill.
4
+ metadata:
5
+ docs: https://nifra.dev/docs/verification
6
+ ---
7
+
8
+ # Nifra: the gates
9
+
10
+ Nifra turns "did you do this right" into build failures. The gates exist so an agent can check its own
11
+ work instead of asserting success. Run them; do not route around them.
12
+
13
+ ## The done-gate
14
+
15
+ ```sh
16
+ nifra check --json # or the nifra_check MCP tool
17
+ ```
18
+
19
+ `nifra check` typechecks the frontend/backend contract and flags drift: a hand-rolled `fetch()` at
20
+ this app's own API, a server-only import inside `routes/`, a client call whose route changed shape.
21
+ Findings carry the fix.
22
+
23
+ **A failing check means the work is not done.** Do not suppress a finding, widen a type, or add a
24
+ cast to make it pass. If a finding is genuinely wrong for this codebase, say so explicitly to the
25
+ person you are working for rather than quietly silencing it.
26
+
27
+ `nifra doctor` is the other half: environment and build-state problems (stale `dist/`, duplicate
28
+ framework install, misconfigured adapter) that make correct code behave wrongly.
29
+
30
+ ## Security evidence per route
31
+
32
+ ```sh
33
+ $ nifra assure
34
+ ✖ POST /notes (authenticated-write) is missing nifra.authenticated
35
+ ```
36
+
37
+ A policy file classifies every route by reflection, then `assure` fails CI naming exactly which
38
+ evidence is absent: authentication on a write, a rate limit, CSRF, a body cap. When you add a route,
39
+ you add its evidence in the same change. When `assure` names a gap, add the real control - never
40
+ reclassify the route to make the requirement disappear.
41
+
42
+ ## Effect provenance
43
+
44
+ Routes declare the effects they perform:
45
+
46
+ ```ts
47
+ app.post("/notes", { capabilities: ["db.write"] }, handler)
48
+ ```
49
+
50
+ `nifra capabilities check` compares what a route *declares* against what its module graph can
51
+ actually *reach*, pinned in a lockfile. A `GET` that can reach a domain write is an error.
52
+
53
+ The common cause of a surprise failure is a barrel file: importing one helper from `./lib` drags the
54
+ whole module graph's reach into the route. The fix is to narrow the import, not to widen the
55
+ declaration.
56
+
57
+ ## Deploy promotion
58
+
59
+ `nifra manifest diff` emits one hash-verified artifact - contracts, assurance, effects, response
60
+ sensitivity - and fails closed on a breaking contract change, lost assurance, or a newly exposed
61
+ sensitive field. Run it between environments, not just at merge.
62
+
63
+ ## Testing
64
+
65
+ `@nifrajs/testing` derives tests from the contract rather than from your assumptions:
66
+ adversarial/hostile input generation, response conformance, replay, shrinking, and a runtime-matrix
67
+ check that the same app behaves identically on Bun, Node, Deno, and Workers.
68
+
69
+ Prefer a contract-derived test to a hand-written one that re-asserts the schema. Hand-write the tests
70
+ covering business rules the contract cannot express.
71
+
72
+ ## The verification ladder
73
+
74
+ Five cumulative levels, from "has a typed contract" up to "has contract-derived invariant tests".
75
+ `nifra levels` (or `nifra_levels`) reports where the project actually stands.
76
+
77
+ Use it honestly: report the level the project holds, not the one it aspires to. Raising a level means
78
+ adding the evidence, not editing the claim.
79
+
80
+ ## Suggested CI order
81
+
82
+ ```sh
83
+ nifra check # contract drift
84
+ nifra assure # route security evidence
85
+ nifra capabilities check
86
+ bun test # incl. contract-derived tests
87
+ nifra manifest diff # promotion gate, between environments
88
+ ```
89
+
90
+ Fail the build on each. A gate that only warns is a gate that gets ignored.
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: nifra-web
3
+ description: Use when building the full-stack side of a Nifra app - file routes, layouts, loaders and actions, forms, server functions, streaming SSR, islands, SSG and ISR, the query cache, and the React, Vue, Solid, Svelte, or Preact render adapters. Covers the client/server boundary rules and the hydration errors that boundary produces. Load after the `nifra` skill.
4
+ metadata:
5
+ docs: https://nifra.dev/docs/routing
6
+ ---
7
+
8
+ # Nifra: full-stack rendering
9
+
10
+ `@nifrajs/web` is the framework-agnostic SSR core; `@nifrajs/web-react`, `-vue`, `-solid`,
11
+ `-svelte`, and `-preact` are render adapters over the same routing, loaders, streaming, and islands.
12
+ Switching UI library is an adapter import, not a rewrite.
13
+
14
+ Call `nifra_context` first in an existing app: it returns the actual route tree and conventions, which
15
+ beats inferring them from a directory listing.
16
+
17
+ ## Data flows one way
18
+
19
+ ```
20
+ route file -> loader (server) -> component (server render, then hydrate) -> action (server) -> revalidate
21
+ ```
22
+
23
+ - **Loader** - runs on the server for the matched route. Returns typed data to the component. Reach
24
+ your own API through `ctx.api` (an in-process client - no HTTP hop, no base URL, no auth replay).
25
+ - **Action** - handles a mutation, then revalidation refreshes the loaders that matter.
26
+ - **Component** - renders on the server, then hydrates. It must be safe to run in both places.
27
+
28
+ Do not `fetch()` your own backend from a loader. `ctx.api` is the in-process path and it is typed.
29
+
30
+ ## The boundary is enforced, not advisory
31
+
32
+ A server-only module that reaches the browser bundle is a **build error**. That is deliberate:
33
+ leaking a DB client or a secret into client JS is the failure mode this prevents.
34
+
35
+ Signals and their causes:
36
+
37
+ | Error | Cause |
38
+ |---|---|
39
+ | `... reached the client bundle` | A `node:` or native import pulled in from a component or route module |
40
+ | `server-only module reached the client bundle` | A module carrying the server-only marker was imported from client code |
41
+ | `resolveDispatcher` / `Invalid hook call` | Two copies of the UI framework. The adapter dedupes it at build time - a stale `dist/` or a second install is the usual source |
42
+
43
+ Fixes: move the server work into a loader, an action, or a server function; keep secrets in modules
44
+ the client never imports; rebuild before blaming the code.
45
+
46
+ **Server functions** are the escape hatch that stays safe: write the function on the server, call it
47
+ from a component. The module body never ships, the arguments are validated, and the mounted function
48
+ is an ordinary route - so assurance, capabilities, and the effect ledger still apply to it.
49
+
50
+ ## Forms work before hydration
51
+
52
+ There is a window between HTML arriving and JS booting. Nifra keeps it usable: progressive-enhancement
53
+ forms and links function during it, and a JS-only form whose native submit would break is guarded
54
+ automatically. Do not disable a submit button until hydration; do not build a form that only works
55
+ after JS. If you add `onSubmit` with `preventDefault`, make sure the action still handles a native
56
+ POST.
57
+
58
+ ## Rendering modes
59
+
60
+ - **SSR** - per-request render. The default.
61
+ - **Streaming** - Suspense plus `defer()`, on every runtime including the edge. Stream the slow part;
62
+ do not block the shell on it.
63
+ - **SSG / ISR** - prerender static routes, enumerate dynamic ones, cache with stale-while-revalidate.
64
+ - **Islands** - ship interactivity for one component instead of the page.
65
+
66
+ ## Query cache
67
+
68
+ `useQuery` / `createQuery` (naming follows the adapter's idiom): keyed cache, dedup, staleness,
69
+ invalidation. Use it rather than a `useEffect` fetch. An action's revalidation and the query cache
70
+ are the same invalidation story - do not run a second, hand-rolled one alongside them.
71
+
72
+ ## Dev loop
73
+
74
+ ```sh
75
+ nifra dev # Vite-backed HMR, state preserving
76
+ nifra build
77
+ nifra start
78
+ ```
79
+
80
+ `@nifrajs/web/dev` is the Bun-native HMR loop with no Vite dependency. Production builds use Bun.
81
+
82
+ If dev behaviour disagrees with a fresh build, suspect a stale `dist/` before suspecting the code -
83
+ run `nifra doctor`.
84
+
85
+ ## Common mistakes
86
+
87
+ | Mistake | Do instead |
88
+ |---|---|
89
+ | `fetch("/api/...")` in a loader | `ctx.api` |
90
+ | Data fetching in `useEffect` | Loader, or the query cache |
91
+ | Importing a DB client into a route component | Loader, action, or server function |
92
+ | Blocking the whole page on one slow query | `defer()` plus Suspense |
93
+ | Adding a second copy of React/Vue to fix a resolution error | Rebuild; the adapter dedupes at build time |