---
title: Architecture
description: One declarative agent table, layered modules, and a registry client — how sks is built.
status: draft
sidebar:
  order: 1
---

```
commands / flows (presentation)
        │
        ▼
      core (policy: upload resolution, versioning, auth resolution)
        │
        ├── packaging (tar, atomic swap, provenance, registry lookup)
        ├── features  (agent table, loaders, install engine, manifests)
        └── api       (registrar client, auth ladder)
        │
        ▼
      utils
```

Dependencies point strictly downward; `core` never imports from the CLI
layer, and interactive flows are pure presentation with injected callbacks.

## The agent table

Every supported agent is one row in a declarative table: its directory,
instructions filename, MCP emitter, capabilities, and support tier
(`supported` / `experimental`). Adding an agent means adding a row plus
tests — no conditionals in shared code. Help text and the agent matrix
derive from the table.

## Install model

A skillset in `~/.nori/profiles/` is the source; activation translates it
through per-agent loaders (instructions, skills, subagents, slash commands,
MCP) into the agent's directory, marks it with `.nori-managed`, and records
SHA-256 manifests per (agent, directory) for local-change detection.
Non-destructive invariants: settings files merge rather than clobber,
external files get `.pre-nori` backups, updates swap atomically, downloads
verify checksums.

## Registry client

The registrar API is npm-shaped: packuments, dist-tags, tarballs. Auth
resolves through a strict ladder — `NORI_API_TOKEN` env, config API token,
unexpired Firebase ID token, refresh-token exchange, legacy password —
and org-scoped tokens are never sent cross-registry.

## Contributing

Node 22, Commander, vitest (colocated tests), eslint + prettier + tsc. The
repo's AGENTS.md carries a test-enforced "How to Close the Loop" section —
every change class has a concrete end-to-end verification path. Releases
are CI-only via npm trusted publishing (`skillsets-v*` tags → latest;
main → `@next`).
