# Agentic Content Infrastructure SDK

Agentic Content Infrastructure (ACI) sites implement the frontend contract by
installing `@gradial/aci`, Zod 4, and TypeScript tooling. The
SDK exposes component and layout helpers, renderer types, compiler tooling,
content provider helpers, and framework-specific subpaths from one package.

```bash
npm install @gradial/aci zod@^4
npm install -D typescript tsx
```

Common imports:

```ts
import { defineComponentContract, defineLayoutContract, slot } from '@gradial/aci';
import type { GradialRenderer } from '@gradial/aci';
import type { KernelPage, KernelSiteConfig } from '@gradial/aci/content';
import { createContentSchemas, stringField } from '@gradial/aci/content';
import { FileContentProvider } from '@gradial/aci/providers/file';
```

Content contract helpers are also available through focused subpaths:
`@gradial/aci/content/contract`, `@gradial/aci/content/validation`, and
`@gradial/aci/content/tailwind-validator`.

Framework helpers live under `@gradial/aci/astro`,
`@gradial/aci/next/server`, `@gradial/aci/next/middleware`,
`@gradial/aci/next/dev-refresh`, and `@gradial/aci/sveltekit`.

## Component Contracts vs Runtime Components

Keep compile-time CMS contracts separate from runtime component implementation.
The ACI compiler imports only contract files, so those files must not import
React, framework components, CSS, or browser-only code.

Recommended shape:

```txt
src/cms/contracts/components/hero.contract.ts
src/cms/contracts/components/index.ts
src/cms/contracts/layouts/index.ts
src/components/Hero.tsx
src/cms/renderBlock.tsx
```

Contract files own names, schemas, render modes, image slots, and other metadata:

```ts
import { defineComponentContract, GradialImageSchema } from '@gradial/aci';
import { z } from 'zod';

export const heroContract = defineComponentContract({
  name: 'hero',
  schema: z.object({
    headline: z.string(),
    image: GradialImageSchema,
  }),
  renderModes: { canStatic: true, canSSR: true, canClientIsland: false },
});

export type HeroProps = z.infer<typeof heroContract.schema>;
```

Runtime components may import the contract for types, but contract files should
never import runtime components:

```tsx
import type { HeroProps } from '../cms/contracts/components/hero.contract';

export function Hero(props: HeroProps) {
  return <section>{props.headline}</section>;
}
```

Testing helpers live under `@gradial/aci/testing`:

```ts
import { FixtureContentProvider } from '@gradial/aci/testing';

const content = new FixtureContentProvider({
  pages: {
    '/': {
      id: 'home',
      $type: 'page',
      status: 'published',
      layout: 'marketing',
      renderMode: 'static',
      metadata: { title: 'Test Home' },
      regions: { main: [] }
    }
  }
});

const input = await content.loadRenderInput('/');
```

Use this in unit tests when you want the same provider API as
`FileContentProvider` without creating `.content` fixture files.

Publish from this package directory:

```bash
npm publish --access public
```

The package includes a `prepack` script that builds `dist` before packing or
publishing.

## Verify the Published Shape Locally

Before publishing, inspect the exact tarball npm will upload. This catches
package `files` mistakes where local source imports work from the repo but fail
after npm filters the packed files.

From `packages/sdk`:

```bash
tmpdir="$(mktemp -d /tmp/gradial-aci-pack.XXXXXX)"
filename="$(npm pack --pack-destination "$tmpdir" | tail -n 1)"
tar -tzf "$tmpdir/$filename" | sort | rg '^(package/src/cli/|package/src/types/|package/dist/types/)'
echo "tarball=$tmpdir/$filename"
```

If a shipped source CLI imports another source file, make sure both paths appear
in the tarball. For example, `src/cli/compile-registry.mjs` imports
`src/types/image.ts`, so both files must be included by `package.json#files`.
