A rough overview of the Agents Inc. CLI codebase. For granular implementation details, see the verified documentation in .ai-docs/.
Agents Inc. CLI (agentsinc) is a TypeScript CLI that manages AI agent configurations for Claude Code. It loads skill definitions from a marketplace, lets users select technology stacks via an interactive terminal wizard, compiles agent prompts from Liquid templates with selected skills injected, and installs the results as Claude plugins or local files.
| Layer | Library | Purpose |
|---|---|---|
| CLI Framework | oclif | Command parsing, flags, plugins, hooks |
| Terminal UI | Ink + React | Interactive wizard, terminal rendering |
| State Management | Zustand | Wizard step state and selections |
| Schema Validation | Zod | Runtime validation at parse boundaries |
| Template Engine | LiquidJS | Agent prompt compilation from partials |
| Config Loader | jiti | TypeScript config files loaded at runtime |
| YAML | yaml | Metadata and matrix parsing |
| Utilities | Remeda | Functional array/object transformations |
| File System | fs-extra + fast-glob | File operations and globbing |
| Testing | Vitest | Unit, integration, command, and E2E tests |
src/
agents/ # Agent source partials (YAML + markdown per agent)
cli/
commands/ # oclif command classes (build, config, import, new, + top-level)
components/ # Ink React components
common/ # Shared UI (confirm, spinner, select-list)
hooks/ # React hooks for wizard behavior
wizard/ # Multi-step wizard components
hooks/
init.ts # oclif init hook (source resolution, dashboard)
lib/ # Core business logic (no UI)
agents/ # Agent fetching, compilation, recompilation
configuration/ # Config loading, merging, generation, source management
installation/ # Install mode detection, local installer, scope-aware config splitting
loading/ # Source fetching, matrix loading, multi-source tagging
matrix/ # Matrix provider (skill lookups), relationship resolution
plugins/ # Plugin discovery, validation, manifest, versioning
skills/ # Skill fetching, copying, metadata, source switching
stacks/ # Stack loading, resolution, compilation
wizard/ # Build step logic (pure functions, no UI)
compiler.ts # Liquid template engine for agent compilation
schemas.ts # All Zod schemas (30+)
exit-codes.ts # Named exit code constants
stores/
wizard-store.ts # Zustand store for wizard state + actions
types/ # TypeScript type definitions (agents, config, matrix, plugins, skills, stacks)
generated/ # Auto-generated union types and built-in matrix from skills source
utils/ # Cross-cutting utilities (errors, exec, fs, logger, type-guards)
config/ # Data config (stacks definitions)
templates/ # Built-in Liquid templates for agent compilation
e2e/ # End-to-end tests (commands, interactive, lifecycle, integration, smoke)
1. User runs command (e.g., `agentsinc init`)
2. oclif init hook runs
-> Extracts --source from raw argv
-> resolveSource() determines skills source
-> Attaches ResolvedConfig to oclif config object
3. Command loads skills matrix
-> loadSkillsMatrixFromSource() fetches categories, rules, skills
-> Returns SourceLoadResult (merged matrix + source config)
4. Wizard renders (Ink/React)
-> Zustand store manages step-by-step state
-> Steps: stack -> skills -> sources -> agents -> confirm
-> Returns WizardResultV2 (selected skills, agent configs, scope settings)
5. Installation
-> installLocal() or installPluginConfig()
-> Copies skills to project, generates TypeScript config
-> writeScopedConfigs() splits config into global + project scopes
6. Compilation
-> Reads agent partials (intro.md, workflow.md, etc.)
-> Builds template context from selected skills
-> Sanitizes to prevent Liquid injection
-> LiquidJS renders agent.liquid template
-> Output: .claude/agents/{name}.md
-
BaseCommand: All commands extend
BaseCommandwhich provides the--sourceflag,sourceConfiggetter (populated by init hook), and error handling with namedEXIT_CODES. -
Init hook: Runs before every command. Resolves the skills source and attaches config to oclif's config object. When no command is given and a project is already initialized, shows a dashboard.
-
Source resolution precedence:
--sourceflag >CC_SOURCEenv var >.claude-src/config.ts(project) >~/.claude-src/config.ts(global) > default marketplace. -
Install modes: Skills can be installed as Claude plugins (managed by Claude's plugin system) or locally (copied to
.claude/skills/). Agents are always written to.claude/agents/. Config is always at.claude-src/config.ts. -
Liquid template compilation: Agent prompts are compiled from partials using LiquidJS. Template root resolution checks project-level overrides first, then built-in templates.
-
Zod at boundaries: All YAML/JSON parsing uses Zod schemas from
schemas.ts. Lenient schemas (.passthrough()) at loading boundaries, strict schemas for validation. Bridge pattern (z.ZodType<ExistingType>) ensures runtime matches compile-time types. -
Multi-source system: Skills can come from multiple sources (public marketplace, private repos, local files). Each
ResolvedSkilltracks all available sources and which is active. Users can mix public skills with private alternatives per-skill via the wizard's Sources step. -
Generated types: Union types (
SkillId,Domain,Category,AgentName, etc.) are auto-generated from the skills source intotypes/generated/. Runtime type guards validate strings against these unions.
Source resolution follows a 5-tier precedence (flag > env > project > global > default). Project config is TypeScript loaded via jiti:
// .claude-src/config.ts
import { defineConfig } from "@agents-inc/cli/config";
export default defineConfig({
skills: [
{ id: "web-framework-react", scope: "project" },
{ id: "web-styling-tailwind", scope: "global" },
],
agents: [{ name: "web-developer", scope: "project", model: "sonnet" }],
});| Install Mode | Skills Location | Agents Location | Config |
|---|---|---|---|
| local | .claude/skills/ |
.claude/agents/ |
.claude-src/config.ts |
| plugin | Claude plugin cache | .claude/agents/ |
.claude-src/config.ts |
Agent prompts are assembled from partials (YAML frontmatter + markdown sections like intro.md, workflow.md, skills.md). The compiler reads agent definitions, builds a template context with all selected skills injected, sanitizes user-controlled fields to prevent Liquid injection ({{, {% stripped), and renders through LiquidJS. Output is one markdown file per agent in .claude/agents/.
| Layer | Config Project | Scope |
|---|---|---|
| Unit | unit |
Pure functions, isolated logic with mocked deps |
| Integration | integration |
Cross-module interactions, real file system |
| Commands | commands |
oclif command execution via runCommand() |
| E2E | e2e/vitest.config.ts |
Full CLI flows with real terminal interaction |
E2E tests cover 5 categories: commands, interactive wizards, lifecycle flows, integration scenarios, and smoke tests. Test data uses factories from __tests__/helpers.ts and canonical fixtures from __tests__/mock-data/.
- Strict TypeScript with zero-
anypolicy. No@ts-ignorewithout justification. - Named exports only (no default exports).
.jsextensions on relative imports. - kebab-case for all files and directories.
- Zod at parse boundaries for all external data (YAML, JSON, CLI args).
- Remeda over imperative loops for data transformations.
- Domain-driven modules in
lib/with barrelindex.tsexports. - Named constants for exit codes, paths, colors, symbols, file size limits (no magic numbers).
- Type guards (
isCategory(),isDomain(), etc.) instead ofascasts for runtime narrowing.