# spartan splits an Angular UI library into behavior you install and markup you own

> An Nx monorepo where the headless brain ships to npm, the styled helm is copied into your repository, and a separate MCP server feeds the docs to AI assistants.

**spartan-ng/spartan** — Cutting-edge tools powering Angular full-stack development.

- Repository: https://github.com/spartan-ng/spartan
- Website: https://spartan.ng
- Stars: 2,917 · Forks: 315
- Language: TypeScript
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/spartan-ng-spartan

## Two products sharing one Angular monorepo

GitHub reports spartan-ng/spartan as a TypeScript project with 2917 stars, 315 forks and 85 open issues, pushed on 2026-09-22 under an MIT license. Its topic list names accessibility, analogjs, angular, trpc and ui-components, which is a fair hint that more than one thing lives here. The README confirms it: the repository is an Nx monorepo home to spartan/ui, a set of accessible un-styled UI primitives for Angular with copy-paste shadcn-style helm styles, and to spartan/stack, an opinionated full-stack setup built on AnalogJs.

The two products share a visual language and a component vocabulary but they are not two halves of one package. spartan/ui is the component library, and the README describes it as version 1.0 and stable, production-ready, semantically versioned, shipping more than 55 components. spartan/stack is a project template that assembles a working application, which is a different kind of artifact with a different lifecycle. A team can adopt the first without ever touching the second.

The monorepo root itself is not a published artifact. The root package.json is marked private with version 0.0.0, so nothing installs from the repository root. Version numbers live on the individual libraries under libs/, and the tree confirms the expected layout with apps/, libs/, tools/ and a skills/ directory alongside the Nx configuration files nx.json, project.json and tsconfig.base.json.

Two other root entries explain the workflow before you read a single script. CLAUDE.md sits in the tree, which means the project keeps agent instructions in version control. V1-TODO.md does the same for planning, which is a useful signal when you are deciding whether a rough edge is a bug or a deliberate gap.

## Why the brain installs but the helm does not

Three packages are published to npm, and the division between them carries the design. @spartan-ng/brain holds the headless, accessible UI primitives, described in the README table as the behavior half of spartan. @spartan-ng/cli is an Nx plugin and a set of Angular schematics that add spartan/ui to any workspace in one go. @spartan-ng/mcp is a Model Context Protocol server that gives AI assistants up to date spartan documentation.

What is deliberately absent from that list is the styled component layer. The README states plainly that the styled helm components are not published as a package on purpose, because the CLI copies them straight into your project so you own and customize every line. The styled components are the part a design system team wants to edit, and a package would freeze them behind a version boundary. Copying them in makes them ordinary source files under your own version control.

That gives you a concrete mental model. The brain package is the thing you depend on and upgrade; the helm files are the thing you fork once and maintain. When a component is fixed upstream, the fix reaches you by re-running the CLI and reviewing the diff, not by waiting on a semver bump.

The README points at two npm packages for a working install, and the command below is the straightforward reading of that instruction:

```bash
npm install @spartan-ng/brain @spartan-ng/cli
```

If you are working inside an existing Angular workspace, the CLI is the entry point rather than a manual copy, because it is packaged as Nx schematics and can generate the helm files where your project expects them.

## Reading the Nx workspace through its scripts

The root package.json is the most honest description of the monorepo, because it names every task the maintainers run themselves. The dev and start scripts both resolve to nx serve app, so the documentation application is what boots in development. Storybook has its own pair of scripts, nx storybook ui-storybook and nx build-storybook ui-storybook, targeted at a project named ui-storybook. Tests, lint and end to end runs all go through nx run-many with project filters rather than bespoke tooling.

The build script is the one worth stopping on:

```bash
NODE_OPTIONS=--max-old-space-size=6000 nx run-many --target build --all --parallel=1
```

A 6 GB heap cap and parallelism pinned to one are not defaults you inherit; someone hit a memory ceiling while building every project at once and left the fix in the script. The `--parallel=1` flag also means local builds are deliberately serialized, so expect the full build to take time even on a fast machine.

Project selection uses tags rather than names in the release paths, which keeps the scripts stable when libraries are added or renamed. The end to end script filters on tag:scope:e2e, and there is a dedicated smoke target, nx run cli-smoke:smoke, that exercises the CLI in isolation. A separate drizzle script generates database migrations from apps/app/drizzle.config.ts, which tells you the documentation application has a real backend rather than static content.

Documentation work has its own generated artifacts. There is a script to generate UI docs and a test that snapshots them, plus another that updates a component preview. If you contribute, expect to run the generator and commit the result instead of editing generated files by hand.

## Three scoped release passes and a changelog you did not write

The release script is a chain of three independent passes, and each one selects its projects by tag:

```bash
"release": "pnpm run release-ui && pnpm run release-cli && pnpm run release-mcp"
```

The ui pass resolves to nx run-many --target=release --projects=tag:scope:brain --parallel=1, which is worth noticing. The pass named for the user facing UI ships the brain package. The styled helm has nothing to release because those files were never in a package. The cli and mcp passes target tag:scope:cli and tag:scope:mcp in the same way.

Versions are set before any of that runs. The prepare-manual-release script calls a generator named set-release-version, then runs lint with a fix flag, then calls hlm-to-cli-generator, which appears to be what copies helm definitions into the CLI's template payload. That last step is the mechanical explanation for the copy-in behavior the README describes: the shipped CLI carries the styled files as data.

The changelog is generated too. The changelog script invokes conventional-changelog with the Angular preset and writes into CHANGELOG.md, and commitlint.config.cjs in the tree means commit messages are checked against the same convention. release.config.mjs sits alongside it. The practical consequence for you as a consumer is that the changelog is trustworthy as a record of what changed, and release notes are the right place to look before upgrading rather than reading the source diff.

A .verdaccio directory in the tree points at a local npm registry used to rehearse the publish flow before anything reaches the public registry. That is standard practice for packages with several moving parts, and it is a sign the maintainers treat publishing as something worth testing rather than assuming.

## The docs site, the MCP server and the drizzle schema

Three details in the tree and scripts show that this repository is more than a component library with good intentions. The drizzle script generates migrations against apps/app/drizzle.config.ts, so the application behind spartan.ng owns a database. The topic list includes trpc, and analogjs, which is the full-stack Angular meta-framework the stack product is built on. Together they describe an application that reads and writes rather than a static docs folder.

Then there is @spartan-ng/mcp, published as its own npm package and described as a Model Context Protocol server that gives AI assistants up to date spartan documentation. For a library whose recommended usage is copying component source into a repository, this is a coherent addition. If your assistant is writing the helm code, giving it the real current API surface matters more than most documentation tooling, because the failure mode of copy-in libraries is usually an assistant inventing prop names for components it half remembers.

The MCP package is also a maintenance commitment. Documentation that ships as a service has to track releases, and the package sits in the same tag-scoped release pipeline as brain and cli, so a version bump of the component library and a refresh of the assistant-facing docs can be reasoned about together.

The skills/ directory at the root is a second signal in the same direction. Projects that want agents to work well inside their codebase have started shipping skill definitions next to the source. Whether spartan's skills target contributors to the monorepo or consumers of the library is not stated in the README, so treat that as an open question if you are evaluating it.

## What the 1.5.0 notes actually changed

The three most recent releases all landed within hours of each other on 2026-09-21, which is normal for a semantic-release setup that publishes a stable tag and two pre-release tags from one batch of merges. Reading them in order shows what the project considers finished work.

The beta builds carried the fixes. v1.5.0-beta.8 added a data-testid attribute to the sonner component for end to end testing, which is a small change with a clear purpose: it gives the e2e suite a stable selector. v1.5.0-beta.9 fixed accessibility and focus handling for select, autocomplete and combobox, and the entry closes a long list of issue numbers at once, which usually means one underlying focus management fix resolved a family of reports.

The stable v1.5.0 then added a new component pair. The message scroller gained both brain and helm halves, which is the shape every addition should follow in this project: behavior in the package, styled markup in the template payload. Sonner gained an ng-template for its action and cancelAction slots, moving control of those buttons from fixed markup to caller-provided templates. The switch component changed shape too, with brn-switch-thumb becoming a directive and a forceInvalid option added to brn-switch.

That switch change deserves attention from anyone with existing code. Turning a thumb into a directive alters how you query and compose it, and forceInvalid is the kind of option that exists because a real form integration needed to bypass normal validity handling. Read the changelog entry for your component before upgrading, since the copy-in model means you hold the old helm source until you deliberately re-run the CLI.

## Where the README and the repository disagree

One discrepancy in this repository is worth naming rather than smoothing over. A README section is titled The 300 spartans, and the sentence under it says the initial 300 contributors and sponsors are featured there. The numbered list underneath that sentence stops at 88.

Both facts come from the same README, so neither is a GitHub metadata artifact to be explained away. The most likely mechanism is visible in the repository itself: the package.json contains a script called update-contributors that regenerates the contributor list, so the block is produced by tooling rather than written by hand. That makes the 88 a snapshot of whatever input that generator reads, and the 300 a target or a milestone rather than a count of the current list.

What this means practically is small but real. Do not read the 88 names as the complete contributor roll, and do not treat the number 300 as a verifiable count. If contributor attribution matters to your evaluation of a project, the useful check is the commit history and the npm package metadata, not this README section.

A second, milder mismatch runs the other direction. The README describes spartan/ui as version 1.0 and stable, while the newest release tag is v1.5.0. These are consistent in the usual semver reading, where 1.0 means the first stable major line and later 1.x releases continue it. But if you are looking for evidence that the library has moved on, the README sentence is a lagging indicator and the release tags are the current one. The repository is not archived, the default branch is main, and the last push recorded was 2026-09-22, one day after the 1.5.0 release.

## Conclusion

spartan is easiest to judge once you separate its two products. spartan/ui is a component library with an unusual ownership model: the behavior half arrives as a versioned npm package and the styled half lands in your repository as files you can edit forever. spartan/stack is a separate opinionated full-stack setup on AnalogJs that borrows the same visual language. Neither half is published the conventional way, and that is stated in the README rather than hidden. The three packages on npm, the tag-scoped release scripts and the generated contributor list all point at one conclusion: the project optimizes for the code living in your workspace. Try the CLI on a scratch branch first, pin the brain package, and keep the helm files under version control so an upgrade is a diff you can read.

## FAQ

### Does spartan publish its styled components to npm?

No, and the README says that is deliberate. The styled helm components are copied into your project by the CLI so you own and customize every line, while the headless brain package, the CLI itself and the MCP server are the three published packages.

### What is the difference between spartan/ui and spartan/stack?

spartan/ui is the component library of accessible, un-styled Angular primitives with copy-paste shadcn-style helm styles, described as 1.0, stable and semantically versioned. spartan/stack is a separate opinionated full-stack setup built on AnalogJs. You can adopt the library without adopting the stack.

### Why does the README call spartan/ui version 1.0 when the newest release is 1.5.0?

The README describes the 1.0 stable major line rather than pinning an exact version, so 1.5.0 is a later release on that same line. For the current version, the release tags are the reliable signal rather than the README sentence.

### What does the @spartan-ng/mcp package do?

It is a Model Context Protocol server that gives AI assistants up to date spartan documentation. It ships as its own npm package and is released through the same tag-scoped pipeline as the brain library and the CLI.

## Sources

- [License: MIT](https://github.com/spartan-ng/spartan/blob/main/LICENSE)
- [Project website](https://spartan.ng)
- [README](https://github.com/spartan-ng/spartan/blob/main/README.md)
- [Releases](https://github.com/spartan-ng/spartan/releases)
- [spartan-ng/spartan on GitHub](https://github.com/spartan-ng/spartan)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/spartan-ng-spartan
