system-cli-standards

Standards for how plugin prompt files (skills, agents, commands) invoke and reference the SDD system CLI.

SKILL.md

GitHub

System CLI Standards

Standards for all plugin prompt files (skills, agents, commands) that invoke or reference the SDD system CLI. Does NOT cover hooks (separate lifecycle via hook-runner.sh).


Canonical Invocation

The plugin has two system CLIs — one for core SDD operations and one for tech-pack-specific operations. Each has its own system-run.sh:

# Core SDD operations (spec, scaffolding, workflow, settings, permissions, archive, agent, log, tech-pack)
<plugin-root>/core/system/system-run.sh <namespace> <action> [args] [options]

# Tech pack operations (config, contract, database, local-env)
<plugin-root>/fullstack-typescript/system/system-run.sh <namespace> <action> [args] [options]
  • <plugin-root> is a placeholder that the agent resolves from its Claude Code plugin context. It is NOT shell syntax — the agent substitutes the actual absolute path before constructing the bash command.
  • Each system-run.sh self-locates its own system root from its filesystem path and forwards to the compiled CLI via exec.
  • Both system packages are private: true with no bin field, so system-run.sh is the only valid way to invoke each.

Which CLI to call

Namespace CLI
scaffolding, spec, permissions, workflow, settings, archive, tech-pack, agent, log core/system/system-run.sh
config, contract, database, local-env fullstack-typescript/system/system-run.sh

Invocation Contexts

1. Plugin prompts (skills, agents, commands)

Use system-run.sh as shown above. This is the only context this standard covers.

2. Hooks

Hooks use hook-runner.sh via hooks.json. Different lifecycle, different stdin/stdout JSON contract. Out of scope for this standard.

3. User-project npm scripts (scaffolded templates)

Templates that scaffold package.json files into user projects cannot use ${CLAUDE_PLUGIN_ROOT} — that variable only exists during a plugin session. Scaffolded npm scripts that reference sdd-system as a bare command are broken. Until the system package exposes a bin field or another resolution mechanism, do not emit CLI invocations in scaffolded templates. Instead, provide instructions that the user runs via the plugin commands (e.g., /sdd-run).


Output Contract

All CLI commands return a CommandResult:

interface CommandResult {
  readonly success: boolean;
  readonly data?: unknown;
  readonly error?: string;
  readonly message?: string;
}

Behavior by mode

Mode Flag Behavior
JSON (structured) --json Prints JSON.stringify(result, null, 2) to stdout
Plain (human) (default) Prints result.message to stdout, or Error: ${result.error} to stderr on failure

Exit codes

Code Meaning
0 result.success === true
1 result.success === false

How prompts should consume CLI output

  • For structured data: Use --json and parse the JSON output. Check .success before reading .data.
  • For display to user: Omit --json. The CLI prints human-readable text.
  • Error handling: Check the exit code. On non-zero exit, the stderr contains the error message.

Global options

All commands accept:

Option Description
--json Output structured JSON instead of plain text
--verbose Enable verbose logging
--help Show help for the command

Stdin Convention

CLI commands that accept file content (e.g., --config <path>) should also accept - to read from stdin. This eliminates temporary file creation in prompts.

system-run.sh passes stdin through transparently via exec.

Preferred — pipe content via stdin:

echo "${content}" | <plugin-root>/system/system-run.sh namespace action --config -

Avoid — creating temp files:

# Don't do this — creates files that need cleanup
echo "${content}" > /tmp/temp-config.yaml
<plugin-root>/system/system-run.sh namespace action --config /tmp/temp-config.yaml
rm /tmp/temp-config.yaml

Authority Boundaries

CLI owns (deterministic operations)

  • File generation and scaffolding
  • YAML/JSON parsing and validation
  • Path resolution and filesystem checks
  • Schema validation
  • Environment management
  • Configuration reads and writes
  • Version information

Prompts own (judgment and interaction)

  • Orchestration and workflow sequencing
  • User interaction (commands only)
  • Decision-making and context-dependent logic
  • LLM-based analysis and generation
  • Interpreting user intent

Rule

If an operation is deterministic and repeatable, it belongs in the CLI. If it requires judgment or context, it belongs in the prompt.

Layer separation

  • Allowed: prompts → CLI (prompts invoke CLI commands)
  • Forbidden: CLI → prompts (CLI must never reference skills, agents, or commands)

This is a strict one-way dependency. The CLI is a standalone tool that knows nothing about the prompt layer.

Plugin boundary

All plugin prompt files (plugin/core/skills/, plugin/core/commands/, plugin/fullstack-typescript/skills/, plugin/fullstack-typescript/agents/) have no runtime access to anything outside plugin/. Never reference .claude/, .tasks/, or root-level files from within a plugin prompt file.


When to Use CLI vs Prompt Logic

Operation Owner Why
File reading/writing with fixed logic CLI Deterministic, no judgment needed
YAML/JSON parsing with validation CLI Schema-based, repeatable
Path resolution and filesystem checks CLI Pure computation
Scaffolding files from templates CLI Template expansion is mechanical
Configuration management CLI Read/write/validate against schema
Anything requiring LLM judgment Prompt Non-deterministic
Anything requiring user interaction Prompt (command layer) Commands are the UI layer
Workflow orchestration Prompt Sequencing decisions
Interpreting ambiguous requirements Prompt Needs context and judgment

Checklist for New CLI Commands

Before adding a new CLI command, verify:

  • The operation is deterministic and repeatable
  • It does not require LLM judgment or user interaction
  • It fits within an existing namespace, or a new namespace is justified
  • It returns a CommandResult with appropriate success, data, error, and message fields
  • It supports --json for structured output
  • It accepts - for stdin where file content is an input
  • It has proper exit codes (0 success, 1 failure)
  • It does not reference or depend on any prompt files (skills, agents, commands)
  • It is documented in the relevant command .md file that will invoke it

Command Existence Rule

Every system-run.sh <namespace> <action> reference in a prompt file must correspond to a command that actually exists in the CLI registry. Prompt files must not reference nonexistent namespace/action pairs.

Source of truth: Each namespace has a schema.ts in its respective system package — plugin/core/system/src/commands/<namespace>/schema.ts for core namespaces, or plugin/fullstack-typescript/system/src/commands/<namespace>/schema.ts for tech pack namespaces. Each exports an ACTIONS array as the authoritative list of valid actions per namespace.

Enforcement: The cli-invocation-audit.test.ts test scans all .md files under plugin/ for system-run.sh <namespace> <action> patterns and validates each pair against the CLI's actual command registry. This test runs as part of npm test.

When adding a new CLI invocation to a prompt file:

  1. Verify the <namespace> <action> pair exists in the corresponding schema.ts
  2. If the command doesn't exist yet, create it first — never reference a command that doesn't exist

Audit Procedure

How to audit

Use Opus model for audits — thoroughness matters more than speed here.

  1. Read every file in plugin/core/skills/, plugin/core/commands/, plugin/fullstack-typescript/skills/, and plugin/fullstack-typescript/agents/
  2. Also read scaffolded templates in plugin/core/skills/*/templates/ and plugin/fullstack-typescript/skills/*/templates/
  3. For each file, check:
    • Invocation correctness: All CLI references use the canonical system-run.sh invocation
    • Authority violations: Prompts performing deterministic operations that belong in the CLI (e.g., YAML/JSON parsing, file generation, schema validation, path resolution). These are candidates for new CLI commands.
    • Compliance: All other standards in this document are followed
  4. Record every finding with exact file path, line number, and description. Categorize as:
    • Violation: Something that is currently broken or wrong
    • Authority issue: A deterministic operation in a prompt that should be a CLI command (improves speed and reliability)
  5. Write report to .temp/system-cli-audit-<datetime>.md
  6. Ask the user if they want to turn the audit into a task. If yes, copy the report file into the task directory (e.g., .tasks/0-inbox/116/audit-<datetime>.md) and reference it from task.md — do NOT inline the full report into task.md

Note: plugin/core/system/README.md and plugin/fullstack-typescript/system/README.md are the CLIs' own documentation and are out of scope for prompt file audits.

TypeScript standards audit

Audit the plugin/core/system/ and plugin/fullstack-typescript/system/ TypeScript source code against the typescript-standards skill.

  1. Load the typescript-standards skill — use its full Summary Checklist as the audit criteria
  2. Read every .ts file in plugin/core/system/src/ and plugin/fullstack-typescript/system/src/ (recursively)
  3. For each file, check every item in the typescript-standards Summary Checklist
  4. Record every finding with exact file path, line number, and the specific standard violated
  5. Append results to the same .temp/system-cli-audit-<datetime>.md report (under a separate "TypeScript Standards" heading), or write a standalone .temp/typescript-audit-<datetime>.md if running independently