Stack Pack Contract Specification

Formal specification of the StackPack interface that project-convention extensions implement to plug into aidokit.

Field Value
Spec name aidokit Stack Pack Contract
Spec version 1.0 (draft)
Status Pre-alpha — locked structure, types may shift
Targets AI Dev Orchestrator Spec v2.0
Compatible CLI aidokit v0.1+
Sibling spec adapter-contract.md
Last reviewed Pre-publication

Table of contents

  1. Purpose and audience
  2. Document conventions
  3. Concepts and terminology
  4. Stack pack vs adapter — division of responsibility
  5. Lifecycle
  6. The StackPack interface
  7. Supporting types
  8. Method specifications
  9. The StackPackManifest
  10. Detection model
  11. Skill contribution rules
  12. MCP suggestion rules
  13. Validation command rules
  14. Architecture pattern hints
  15. Conformance levels
  16. Worked example: node-ts stack pack
  17. Versioning and compatibility
  18. Migration policy
  19. Security requirements
  20. Open questions
  21. Appendix A: Required outputs by conformance level
  22. Appendix B: Minimum implementation skeleton

1. Purpose and audience

1.1 Purpose

This specification defines the contract every aidokit stack pack MUST satisfy. A stack pack contributes project-convention knowledge for a specific tech stack (Node.js + TypeScript, Python, React, Go, Django, etc.) — detection logic, stack-aware skills, suggested MCPs, validation commands, and optional architecture pattern hints.

This document is normative. Wording follows RFC 2119 conventions.

1.2 Audience

1.3 Non-purpose

This document does NOT specify:


2. Document conventions

2.1 RFC 2119 keywords

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, and REQUIRED are interpreted as described in RFC 2119.

2.2 Type syntax

All types are presented in TypeScript. Stack packs implemented in other languages MUST satisfy the same semantics.

2.3 Reserved namespaces


3. Concepts and terminology

Term Definition
Stack pack A package implementing this contract for one technology stack
Stack A coherent set of language + framework + tooling conventions
Detection The process of determining whether a project uses a given stack
Confidence A categorical score for how strongly a project matches a stack
Skill contribution A SkillTemplate the stack pack provides for adapter emission
MCP suggestion A reference to an MCP catalog id the stack pack recommends
Validation command A shell command suitable for lint/typecheck/test on this stack
Architecture pattern hint A non-binding recommendation about code organization
ProjectContext The immutable context object passed to most methods (defined in @aidokit/core)
DetectContext A lighter context specific to detection (no user selections yet)

4. Stack pack vs adapter — division of responsibility

This section is critical. Stack packs and adapters are siblings; both extend the core but in orthogonal directions.

Concern Owner
Engine directory layout Adapter
Agent rules file format Adapter
Verb / role / hook file emission Adapter
Capability profile enforcement Adapter
MCP installation mechanism (claude mcp add, …) Adapter
Detecting the stack from project files Stack pack
Stack-specific skill templates (e.g., Zod conventions) Stack pack
Which MCPs are useful for this stack Stack pack
Default validation commands (lint, typecheck, test) Stack pack
Optional architecture pattern hints Stack pack

Key rule: Stack packs MUST NOT emit files directly. They contribute data (skills, suggestions, commands) that adapters consume and emit in their CLI's native format. This keeps stack packs portable across adapters — a Django stack pack works the same way whether Claude Code or Codex consumes it.


5. Lifecycle

Stack pack methods are called at different points during aidokit init and other commands.

5.1 During aidokit init

1.  buildDetectContext()
2.  for each installed stack pack:
       result = await stackPack.detect(detectCtx)
       collect (stackPack, result) pairs sorted by confidence
3.  user selects which stack packs to enable
4.  buildProjectContext() including selectedStackPacks
5.  for each selected stack pack:
       skills.push(...stackPack.suggestSkills(ctx))
       suggestedMcpIds.push(...stackPack.suggestMCPs(ctx))
       validationCmds.push(...stackPack.suggestValidationCommands(ctx))
       if conformance >= 'strict' and stackPack.defaultArchitecturePattern:
          hints.push(stackPack.defaultArchitecturePattern(ctx))
6.  pass skills to adapter.emitSkills(ctx, skills)
7.  pass validationCmds into the agent rules file emission
8.  resolve suggestedMcpIds against the catalog → user picks which to install
9.  resolve hints into the architecture-summary doc (if present)

5.2 During aido mcp suggest

1.  for each enabled stack pack:
       ids = stackPack.suggestMCPs(ctx)
       collect ids
2.  filter out already-installed MCPs
3.  display remaining suggestions

5.3 During aidokit sync

Stack pack outputs are recomputed during sync; new skills or updated suggestions may be proposed to the user.

5.4 Determinism

Stack packs MUST be deterministic. Given identical DetectContext/ProjectContext and identical filesystem state, every method MUST produce byte-identical output.


6. The StackPack interface

The normative TypeScript interface. Every stack pack MUST implement every method except those marked optional.

import type {
  StackPackManifest,
  DetectContext,
  DetectionResult,
  ProjectContext,
  SkillTemplate,
  ValidationCommand,
  ArchitecturePatternHint,
} from '@aidokit/core';

export interface StackPack {
  /** Static identity and metadata. */
  readonly manifest: StackPackManifest;

  /** Determine whether the current project uses this stack. */
  detect(ctx: DetectContext): Promise<DetectionResult>;

  /** Stack-specific skill templates for adapter emission. */
  suggestSkills(ctx: ProjectContext): SkillTemplate[];

  /** Catalog MCP ids recommended for this stack. */
  suggestMCPs(ctx: ProjectContext): string[];

  /** Validation commands (lint, typecheck, test) appropriate for this stack. */
  suggestValidationCommands(ctx: ProjectContext): ValidationCommand[];

  /** OPTIONAL: architecture pattern hint (Strict conformance only). */
  defaultArchitecturePattern?(ctx: ProjectContext): ArchitecturePatternHint;
}

7. Supporting types

All types are exported from @aidokit/core.

7.1 DetectContext

Passed to detect(). Lightweight; no user selections yet.

export interface DetectContext {
  /** Absolute path to project root. */
  projectRoot: string;

  /** Whether a file exists at the given path (relative to projectRoot). */
  fileExists(relativePath: string): Promise<boolean>;

  /** Read a file's content (UTF-8). Throws if missing. */
  readFile(relativePath: string): Promise<string>;

  /** Read a parsed package manifest file if recognized; null otherwise. */
  readManifest(
    name: 'package.json' | 'pyproject.toml' | 'Cargo.toml' | 'go.mod' | 'pom.xml' | 'Gemfile',
  ): Promise<ParsedManifest | null>;

  /** Glob within the project root. */
  glob(pattern: string): Promise<string[]>;

  /** Whether the manifest declares a dependency (name match, version-agnostic). */
  manifestHasDep(name: string): Promise<boolean>;

  /** OS info for OS-specific detection. */
  os: 'darwin' | 'linux' | 'win32';
}

Rules:

7.2 DetectionResult

export interface DetectionResult {
  /** Whether the stack was detected. */
  matched: boolean;

  /** Categorical confidence level. */
  confidence: 'high' | 'medium' | 'low' | 'none';

  /** Pack-specific extras (e.g., subframework detection). */
  extras?: Record<string, unknown>;

  /** Human-readable reason explaining the match. */
  reason?: string;
}

Confidence semantics:

Level Meaning
high Multiple strong signals (manifest dep + framework-marker file)
medium One strong signal OR multiple weak signals
low Single weak signal (e.g., a config file but no manifest dep)
none No match (and matched MUST be false)

7.3 SkillTemplate

(Already defined in adapter-contract.md; restated for completeness.)

export interface SkillTemplate {
  id: string;
  name: string;
  source: 'core' | 'stack-pack';
  sourcePackId?: string;
  content: string;
  autoLoadTriggers: string[];
  preloadedBy: RoleName[];
  required: boolean;
}

For stack-pack-contributed skills:

7.4 ValidationCommand

export interface ValidationCommand {
  /** Stable identifier (e.g., 'lint', 'typecheck', 'test'). */
  id: string;

  /** Human-readable label. */
  label: string;

  /** Shell command to run. */
  command: string;

  /** Category. */
  kind: 'lint' | 'typecheck' | 'test' | 'format-check' | 'build' | 'other';

  /** Whether this command is suitable for CI (non-interactive, deterministic exit code). */
  ciSafe: boolean;

  /** Approximate runtime budget category. */
  speed: 'fast' | 'medium' | 'slow';
}

7.5 ArchitecturePatternHint

export interface ArchitecturePatternHint {
  /** Pattern name. */
  pattern:
    | 'mvc'
    | 'controller-service-repository'
    | 'hexagonal'
    | 'clean'
    | 'feature-modules'
    | 'monolithic'
    | 'other';

  /** Short rationale. */
  rationale: string;

  /** Module / directory layout suggestion. */
  suggestedLayout: string[];

  /** Whether this is opinionated (the stack pack strongly recommends) or default (just a hint). */
  strength: 'opinionated' | 'default';
}

8. Method specifications

8.1 detect

detect(ctx: DetectContext): Promise<DetectionResult>

Purpose: Determine whether the current project uses this stack, with a confidence level.

MUST:

SHOULD:

MUST NOT:

Conformance: Minimum


8.2 suggestSkills

suggestSkills(ctx: ProjectContext): SkillTemplate[]

Purpose: Provide stack-specific skill templates that the adapter will emit into the project's skills directory.

MUST:

SHOULD:

MUST NOT:

Conformance: Minimum


8.3 suggestMCPs

suggestMCPs(ctx: ProjectContext): string[]

Purpose: Recommend MCP catalog ids that are useful for this stack.

MUST:

SHOULD:

MUST NOT:

Conformance: Standard


8.4 suggestValidationCommands

suggestValidationCommands(ctx: ProjectContext): ValidationCommand[]

Purpose: Provide validation commands appropriate for the detected stack.

MUST:

SHOULD:

MUST NOT:

Conformance: Standard


8.5 defaultArchitecturePattern (optional)

defaultArchitecturePattern?(ctx: ProjectContext): ArchitecturePatternHint

Purpose: Suggest an architecture pattern for greenfield projects in this stack.

MUST:

SHOULD:

MUST NOT:

Conformance: Strict


9. The StackPackManifest

The static manifest declares identity, capabilities, and conformance.

9.1 Type

export interface StackPackManifest {
  /** Stack pack identifier (kebab-case). */
  name: string;

  /** Human-readable display name. */
  displayName: string;

  /** Primary programming languages targeted. */
  languages: string[];

  /** AI Dev Orchestrator Spec version. */
  specVersion: '2.0';

  /** Version of @aidokit/core the pack was built against. */
  sdkVersion: string;

  /** Declared conformance level. */
  conformance: 'minimum' | 'standard' | 'strict';

  /** This package's own version. */
  packVersion: string;

  /** Maintainer information. */
  maintainer: {
    name: string;
    url?: string;
    email?: string;
  };

  /** Detection signal summary (informational; not enforced). */
  detectionSignals: {
    files?: string[]; // e.g., ["manage.py"]
    manifestDeps?: string[]; // e.g., ["django"]
    configFiles?: string[]; // e.g., ["next.config.js"]
  };

  /** Whether this pack composes with other packs (e.g., react + node-ts). */
  composesWith?: string[]; // other stack pack names that complement this one
}

9.2 Manifest file format

Stack packs MUST ship a stack-pack.md (Markdown with YAML frontmatter) at the package root:

---
name: node-ts
displayName: Node.js + TypeScript
languages: [typescript, javascript]
specVersion: '2.0'
sdkVersion: '^1.0'
conformance: standard
packVersion: '0.1.0'
maintainer:
  name: aidokit core team
  url: https://github.com/your-org/aidokit
detectionSignals:
  files: ['tsconfig.json']
  manifestDeps: ['typescript']
composesWith: ['react', 'next-js', 'vue']
---

# Node.js + TypeScript Stack Pack

(Human-readable description.)

9.3 Manifest exposure

Both forms (file at rest, object at runtime) MUST be consistent. CI MUST verify they match.


10. Detection model

10.1 Composability

Multiple stack packs MAY match the same project. The composesWith field in the manifest documents expected combinations. Detection MUST be independent: a stack pack's detect() MUST NOT depend on whether another pack matched.

Example: A Next.js project would match node-ts (high), react (high), and a hypothetical next-js (high) pack.

10.2 Confidence ranking

When the CLI presents detection results, it MUST:

10.3 Conflicts

Two stack packs MAY suggest contradictory things (e.g., different validation commands for the same id). When this happens, the CLI MUST:

10.4 Manual override

aidokit init --stack <id1,id2,…> skips detection for the named packs. Useful for monorepos or unusual structures.

10.5 No detection ≠ unsuitable

A pack returning matched: false MAY still be useful (e.g., a react pack on a project not yet using React but planning to). Users MAY force-enable packs via --stack.


11. Skill contribution rules

11.1 Placeholder discipline

Stack pack skills frequently encode assumptions that may not match the user's project. To prevent hallucination:

Example skill content:

# Zod patterns

## Schema location <REVIEW REQUIRED>

This project places Zod schemas in `src/schemas/`. Each schema file
is named `<resource>.schema.ts`.

## Refinement style <REVIEW REQUIRED>

Refinements use `.refine()` with explicit error messages...

11.2 Required skill metadata

Each contributed skill MUST set:

{
  id: 'zod-patterns',                        // unique across all skills
  name: 'Zod patterns',                       // display name
  source: 'stack-pack',
  sourcePackId: 'node-ts',                   // matches manifest.name
  content: '...',                            // Markdown body
  autoLoadTriggers: ['src/**/*.ts'],         // file globs that auto-load
  preloadedBy: ['builder', 'tester-reviewer'], // roles that always load it
  required: false,                            // false unless stack cannot function without
}

11.3 Forbidden content

Skills MUST NOT include:

11.4 Skill ID conflicts

A stack pack's skill id MUST NOT match a core base skill id or another active stack pack's skill id. The CLI MUST reject installation if a conflict is detected.


12. MCP suggestion rules

12.1 Catalog only

Stack packs MUST reference MCPs by their catalog id. New MCPs MUST be added to the catalog via the catalog spec; stack packs MUST NOT define MCPs inline.

12.2 Stack-appropriateness

A stack pack SHOULD only suggest MCPs that:

12.3 No security-sensitive auto-suggest

Stack packs MUST NOT suggest MCPs marked securitySensitive: true. Those are user-initiated only.

12.4 Role-scoping handled by catalog

Stack packs MUST NOT include role-scoping in their MCP suggestions. The role-scoping comes from the catalog entry's suggestedFor field. Stack packs only say "this MCP is useful for this stack."


13. Validation command rules

13.1 Use project's own scripts

If the project manifest defines a script matching a conventional id (lint, test, typecheck), the stack pack SHOULD use it:

// Good
{ id: 'test', label: 'Test', command: 'npm run test', kind: 'test', ciSafe: true, speed: 'medium' }

// Avoid (reinvents what the project already declares)
{ id: 'test', label: 'Test', command: 'npx vitest run', kind: 'test', ciSafe: true, speed: 'medium' }

13.2 Detect the package manager

Stack packs SHOULD detect lockfiles to choose the right invocation:

Lockfile Command prefix
pnpm-lock.yaml pnpm
yarn.lock yarn
package-lock.json npm
bun.lockb bun

13.3 Mark non-CI commands

Commands requiring a TTY, network access, or non-deterministic state MUST set ciSafe: false. The adapter uses this to gate which commands run in headless contexts.

13.4 Speed categorization

Stack packs SHOULD categorize commands by speed:

This lets the adapter sequence validation appropriately.


14. Architecture pattern hints

14.1 When to provide

A stack pack SHOULD implement defaultArchitecturePattern only when:

14.2 What the hint becomes

The hint is appended to the project's architecture summary doc (docs/architecture/summary.md or similar) during init, marked <REVIEW REQUIRED>. Users adjust as needed.

14.3 Strength

A stack pack MUST NOT mark a hint as opinionated unless the pattern is canonically associated with the stack.


15. Conformance levels

15.1 Per-method conformance

Method Minimum Standard Strict
detect MUST MUST MUST
suggestSkills MUST MUST MUST
suggestMCPs MAY MUST MUST
suggestValidationCommands MAY MUST MUST
defaultArchitecturePattern MAY MAY SHOULD

15.2 Minimum conformance

A Minimum stack pack provides detection and at least one skill. Useful for niche stacks where MCP suggestions don't apply.

Standard adds MCP and validation suggestions. This is the recommended target for first-party packs and most third-party packs.

15.4 Strict conformance

Strict adds architecture hints. Reserved for stacks with strong community conventions.

15.5 Verification

@aidokit/core exports a stack-pack conformance harness:

import { runStackPackConformanceTests } from '@aidokit/core';
import { stackPack } from './src/index.js';

const results = await runStackPackConformanceTests(stackPack, 'standard');

The harness runs detect() against synthetic fixtures, validates returned SkillTemplate shapes, checks that suggested MCPs exist in the catalog, and verifies validation commands are well-formed. Stack packs MUST run the harness in CI.


16. Worked example: node-ts stack pack

A complete Minimum-to-Standard implementation for Node.js + TypeScript.

// packages/aidokit-stack-pack-node-ts/src/index.ts

import type {
  StackPack,
  StackPackManifest,
  DetectContext,
  DetectionResult,
  ProjectContext,
  SkillTemplate,
  ValidationCommand,
} from '@aidokit/core';

const manifest: StackPackManifest = {
  name: 'node-ts',
  displayName: 'Node.js + TypeScript',
  languages: ['typescript', 'javascript'],
  specVersion: '2.0',
  sdkVersion: '^1.0',
  conformance: 'standard',
  packVersion: '0.1.0',
  maintainer: { name: 'aidokit core team' },
  detectionSignals: {
    files: ['tsconfig.json'],
    manifestDeps: ['typescript'],
  },
  composesWith: ['react', 'next-js', 'vue', 'express'],
};

export const stackPack: StackPack = {
  manifest,

  async detect(ctx) {
    const hasTsConfig = await ctx.fileExists('tsconfig.json');
    const hasPkg = await ctx.fileExists('package.json');
    const hasTsDep = hasPkg && (await ctx.manifestHasDep('typescript'));

    if (hasTsConfig && hasTsDep) {
      return {
        matched: true,
        confidence: 'high',
        reason: 'tsconfig.json present and typescript declared in package.json',
      };
    }
    if (hasTsDep || hasTsConfig) {
      return {
        matched: true,
        confidence: 'medium',
        reason: hasTsDep
          ? 'typescript in deps but no tsconfig.json'
          : 'tsconfig.json but no typescript in deps',
      };
    }
    return { matched: false, confidence: 'none' };
  },

  suggestSkills(_ctx) {
    return [
      {
        id: 'typescript-conventions',
        name: 'TypeScript conventions',
        source: 'stack-pack',
        sourcePackId: 'node-ts',
        content: `# TypeScript conventions

## Strictness <REVIEW REQUIRED>

This project uses TypeScript strict mode...
`,
        autoLoadTriggers: ['src/**/*.ts'],
        preloadedBy: ['builder', 'tester-reviewer'],
        required: false,
      },
      {
        id: 'vitest-patterns',
        name: 'Vitest patterns',
        source: 'stack-pack',
        sourcePackId: 'node-ts',
        content: `# Vitest patterns

## Test file naming <REVIEW REQUIRED>

Tests are colocated as \`*.test.ts\` next to the source...
`,
        autoLoadTriggers: ['**/*.test.ts'],
        preloadedBy: ['tester-reviewer'],
        required: false,
      },
      // ... more skills
    ];
  },

  suggestMCPs(_ctx) {
    return ['context7']; // docs lookup is universally useful
  },

  suggestValidationCommands(ctx) {
    // Detect package manager from lockfile
    const pm = ctx.packageManagerLockfile?.includes('pnpm')
      ? 'pnpm'
      : ctx.packageManagerLockfile?.includes('yarn')
        ? 'yarn'
        : 'npm';

    return [
      {
        id: 'lint',
        label: 'Lint',
        command: `${pm} run lint`,
        kind: 'lint',
        ciSafe: true,
        speed: 'fast',
      },
      {
        id: 'typecheck',
        label: 'Typecheck',
        command: `${pm} run typecheck`,
        kind: 'typecheck',
        ciSafe: true,
        speed: 'fast',
      },
      {
        id: 'test',
        label: 'Test',
        command: `${pm} test`,
        kind: 'test',
        ciSafe: true,
        speed: 'medium',
      },
    ];
  },

  // defaultArchitecturePattern is omitted — Node-TS has no canonical pattern
};

The pack ships via npm:

npm install --save-dev @aidokit/stack-pack-node-ts

The CLI discovers it during init when it scans node_modules for aidokit-stack-pack-* packages.


17. Versioning and compatibility

17.1 Three independent semvers

Same model as the adapter contract:

17.2 Compatibility rules

17.3 Deprecation policy

17.4 Sunset window

Major spec bumps support the previous major for at least two minor aidokit CLI releases.


18. Migration policy

18.1 Migration scripts

Every breaking spec change MUST ship with a migration script in @aidokit/core/migrations. Same model as adapter migrations.

18.2 What migrations cover

18.3 What migrations do NOT cover


19. Security requirements

19.1 No file emission

Stack packs MUST NOT write files directly. They contribute data to adapters. This eliminates an entire class of security concerns (capability declarations, write-path globs) at the spec level.

19.2 No network calls

detect() MUST NOT make network calls. suggestSkills(), suggestMCPs(), and suggestValidationCommands() MUST NOT make network calls. Stack packs are pure functions of ProjectContext (plus filesystem reads for detect).

19.3 No code execution

Stack packs MUST NOT execute project code (no require(), import(), or shell invocations against project files). DetectContext provides only safe read operations.

19.4 No secrets

Skills, validation commands, and MCP suggestions MUST NOT contain credentials, tokens, or any value sourced from environment variables.

19.5 Reporting issues

Security issues in any stack pack SHOULD be reported per the pack's SECURITY.md. For first-party packs, see ../../../SECURITY.md.


20. Open questions

Question Resolution target
Whether detect() should be cached across stack packs (currently re-runs filesystem reads) Spec 1.0 freeze
Whether to support sub-packs (e.g., node-ts/express as a composition) Spec 1.1
How conflicting validation commands from composed packs are merged (currently user-resolved) Spec 1.1
Whether stack packs should be able to override core base skills Spec 1.0 freeze
Whether ArchitecturePatternHint should be machine-readable or include a Markdown blob Spec 1.0 freeze
Whether to add a suggestADRs(ctx) method for stacks with canonical decisions to capture Spec 1.1

Appendix A: Required outputs by conformance level

Minimum

Standard

All of Minimum, plus:

Strict

All of Standard, plus:


Appendix B: Minimum implementation skeleton

Proposed scaffolding script (ships in @aidokit/sdk-stack-pack post-1.0):

npx @aidokit/sdk-stack-pack create elixir-phoenix

✔ Created packages/aidokit-stack-pack-elixir-phoenix/
  ├── stack-pack.md
  ├── src/
  │   ├── index.ts                ← exports stackPack
  │   ├── detect.ts
  │   ├── skills/
  │   │   ├── phoenix-conventions/SKILL.md
  │   │   └── ecto-patterns/SKILL.md
  │   ├── mcps.ts
  │   └── validation.ts
  ├── test/
  │   ├── conformance.test.ts
  │   └── detection.test.ts
  └── package.json

Pre-1.0 (before SDK ships): copy packages/stack-pack-node-ts/ and adapt.


See also