CO

codebase-conventions

Defines mandatory codebase conventions for the scai CLI, covering errors, credentials, and modules.

Install

mkdir -p .claude/skills/codebase-conventions && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/19102" && unzip -o skill.zip -d .claude/skills/codebase-conventions && rm skill.zip

Installs to .claude/skills/codebase-conventions

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Non-negotiable codebase conventions for the scai CLI — module boundaries, error contract, credential handling, agent contract, quality gates. Trigger when writing or modifying code in scai.
189 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Enforce `pnpm` for agent package management
  • Structure code into domain areas and cross-cutting layers
  • Implement structured CLI error handling with hints
  • Manage logging with `consola` respecting output formats
  • Handle credentials securely using `keychain-only`

How it works

The skill defines non-negotiable conventions for the `scai` CLI, covering package management, module structure, error handling, logging, and credential management. It ensures adherence to these rules for all code modifications.

Inputs & outputs

You give it
Code changes in `scai` CLI, command options
You get back
Compliant `scai` CLI code, structured errors, formatted logs

When to use codebase-conventions

  • Developing new scai CLI modules
  • Updating shared infrastructure
  • Maintaining scai quality gates

About this skill

Codebase Conventions — scai

These rules apply to every change. The CLI is published to npm and used by end users (humans and agents) — the bar is high.

Package manager: pnpm for agent work

Agents working in scai use pnpm for everything: install, dev, test, build. Never npm, yarn, bun, or npx in an agent session.

End users install scai via any of npm/pnpm/yarn/bun (per the README and because scai is a public CLI). That's a documentation concern, not an agent-workflow concern.

For one-off binaries, use pnpm exec <bin>.

Module structure

src/ is 20 domain areas plus three cross-cutting layers. A domain area owns one product surface — its API client, task runners, and (where it has one) an index.ts SDK barrel.

src/
├── cli.ts             ← entrypoint; src/program.ts builds the Commander tree
├── commands/          ← Commander command definitions; thin parsers
│   ├── deploy/, serialization/, recipe/, brand/, ...  ← per-area subcommands
│   └── shared.ts      ← shared option helpers
├── config/            ← sitecoreai.cli.json + module schemas, config resolution
├── shared/            ← cross-cutting: errors, logger, spinner, HTTP/GraphQL
│                        transport, telemetry, redaction
└── <domain areas>/    ← deploy, serialization, recipe, brand, brief,
                          campaigns, sites, publishing, content, hygiene,
                          webhooks, workflow, agents, policy, mcp,
                          scripting, sync, auth, authoring, doctor

A typical domain area (e.g. serialization/) holds tasks/ (task runners), an API-client subdir, and an index.ts barrel exporting the SDK surface for that subpath.

Direction of imports:

  • commands/ may import any domain area, config/, and shared/.
  • A domain area may import peer domain areas, config/, and shared/ — never commands/.
  • config/ may import shared/ only.
  • src/shared/ is a leaf — it imports no domain area and no commands/ (type-only @/config imports are allowed). allow-write and env were moved into policy/; content/ must not import publishing/. Those two boundaries killed the former shared↔policy and content↔publishing cycles.
  • tests/unit/architecture/module-boundaries.test.ts enforces those two invariants. It is not a full cycle detector — peer domain areas may still cross-import; the hard rule is that shared/ stays a leaf.

When adding a new command group (like recipe), follow the existing pattern: a parser dir under commands/<group>/, and a peer domain area src/<group>/ if it owns runtime logic.

Error handling: createCliError

Throw structured CLI errors so the top-level handler can render them with hints and exit codes. Pattern (from src/shared/errors.ts):

import { createCliError } from "@/shared/errors";

throw createCliError("Invalid module configuration at ${moduleFile}.", "CONFIG_INVALID", {
  hint: "Fix the module JSON to match the serialization module schema.",
  details,
});
  • First arg: human-readable message
  • Second arg: stable CODE for telemetry/log filtering
  • Options: hint (always include — tells the user the next step), details (structured)

Don't throw new Error("...") from command paths. Reserve raw Error for truly internal/programmer errors.

Logging: consola via toLogger(options)

Commands receive options from commander; convert to a logger via toLogger(options) in serialization/tasks/shared.ts. The logger honors --json, --quiet, --log-file.

  • --json → emit JSON lines, no decoration. No banners, no colors, no spinner. Spinner code paths must check logger.isJson() before starting an ora instance.
  • --quiet → suppress info; warnings + errors still emit.
  • --log-file → also write to file at the given path.

Don't console.log. Don't write color codes outside consola/ora.

Credentials: keychain-only

  • Tokens are stored via keytar in src/serialization/tasks/env/deploy-token.ts (and similar for OAuth tokens) under the sitecoreai-cli service.
  • Never write a token to sitecoreai.cli.json directly. The accessToken / deployToken fields in the example config are placeholders showing where keychain values are loaded into.
  • Env-var overrides (SITECOREAI_DEPLOY_TOKEN, SITECOREAI_ENV_<NAME>_DEPLOY_TOKEN) are read at startup and held in memory only — never persisted.
  • Telemetry: the schema explicitly forbids token-shaped payloads; don't add fields that could leak.

Agent / CI contract

Every command must work non-interactively:

  • Honor --non-interactive (don't prompt; fail fast on missing required input)
  • Honor SITECOREAI_AUTO_WIZARD=0 (skip auto-init/auto-login wizards)
  • Default allowWrite: false on environments — destructive operations require explicit --allow-write or allowWrite: true in config
  • Honor --what-if on push-style operations (preview without applying)
  • --json output is structured + machine-parseable; never include decorative text in JSON-mode output. Wrap your output in buildScaiEnvelope() from @/shared/envelope so consumers can branch on data regardless of which task produced the output. The canonical shape is { command, environment, data, count?, whatIf?, summary?, meta? } — see src/shared/envelope.ts. Direct process.stdout.write(JSON.stringify(...)) of raw payloads is a bug; agents and downstream automation depend on the envelope shape.

Destructive-ops contract (two-layer gate)

Tenant writes (cleanup, workflow mutations, webhook create/delete, etc.) pass through two layers in series:

  1. Library gateensureAllowWrite(root, envName, override?) in src/shared/allow-write.ts. Called from every destructive runner. Throws INPUT_INVALID unless env.allowWrite or the per-call override (typically --allow-write) is set.

  2. MCP boundary gateensureMcpElevationAllowed(root, envName), same module. Called from every MCP write tool's handler before the library runner. Throws AUTH_DENIED if the env has denyMcpElevation: true.

Why the second gate exists: when an MCP write tool is invoked, the registry dispatch has already cleared the host's confirmation UX, so the MCP layer auto-elevates allowWrite: true before calling runners. That makes the library gate effectively a no-op for MCP callers. The boundary gate is what lets an environment opt out of MCP-driven writes without changing CLI behaviour.

Adding a new destructive runner:

  • Call ensureAllowWrite(root, envName, options.allowWrite) (or ensureAllowWrite directly) at the start, after whatIf is checked.
  • Default whatIf: true on the CLI command (preview-first).
  • If you also expose the runner via MCP, the MCP handler must call ensureMcpElevationAllowed(context.resolved.root, context.envName) before delegating. The tests/unit/architecture/ directory has a parity test; consider adding a similar test if you're adding a new MCP write tool.

The runner's library gate stays in place for direct CLI use — don't remove it just because the MCP layer auto-elevates.

Quality gates

CommandWhat it runsWhen to use
pnpm checkformat:check + lint + typecheck + testBefore finishing a session
pnpm testVitest unit testsWhile coding
pnpm test:integrationIntegration tests (gated by SITECOREAI_RUN_INTEGRATION=1)After touching API/auth/config
pnpm smokebuild + spawn CLI smoke checksSanity check before publish
pnpm lint:fixESLint with --fixAfter bigger refactors
pnpm formatPrettier writeBefore commit if not relying on lint-staged

Husky + lint-staged run prettier and eslint --fix on staged files at commit time. Pre-commit failures block the commit; fix and re-stage.

Telemetry

Anonymous, opt-in. The CLI prompts for consent on first use.

  • Schema: telemetry.schema.json
  • Implementation: validates payloads against the schema before sending
  • Fields: command name, duration, version, ci flag, region (CDN-derived)
  • Never add user-identifiable fields, full args, or token-shaped values
  • Disable via SITECOREAI_TELEMETRY=false or DO_NOT_TRACK=1

When adding a command

  1. Define the parser in src/commands/<group>/<name>.ts
  2. Implement the task runner in src/<group>/tasks/<name>.ts (or serialization/tasks/...)
  3. Use toLogger(options) for all output; honor --json
  4. Throw via createCliError with a hint
  5. Add a unit test in tests/unit/... mirroring the source path
  6. If the command hits a real Sitecore API, add an integration test in tests/integration/
  7. If the command writes tokens or sensitive data, double-check no log path leaks them
  8. Regenerate the command reference: pnpm docs:commands (writes docs/commands.md)
  9. Run a changeset: pnpm changeset

Common pitfalls

  • Don't bypass allowWrite: false. It's the safety net that prevents accidents in misconfigured environments.
  • Spinner must respect --json. Starting ora while JSON output is on corrupts the stream.
  • Module schema vs root config schema. Two separate JSON Schema documents in src/config/. Don't confuse them.
  • Error codes are stable contracts. Don't rename a CODE once it's shipped — telemetry and tooling depend on it.
  • **The __Standard values chicken-and-eg

Content truncated.

When not to use it

  • When working outside the `scai` CLI codebase
  • When using `npm`, `yarn`, `bun`, or `npx` for agent sessions
  • When bypassing `allowWrite: false` for destructive operations

Limitations

  • Rules apply only to `scai` CLI
  • Requires `pnpm` for agent work
  • Does not allow `console.log` or raw `Error` throws

How it compares

This skill establishes a strict set of codebase conventions for the `scai` CLI, ensuring consistency and quality that differs from projects with less defined or enforced coding standards.

Compared to similar skills

codebase-conventions side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
codebase-conventions (this skill)013dNo flagsIntermediate
senior-fullstack357moReviewIntermediate
mcp-builder1363moReviewAdvanced
architecture-patterns552moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

senior-fullstack

davila7

Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.

35110

mcp-builder

anthropics

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

136215

architecture-patterns

wshobson

Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.

55214

dependency-upgrade

wshobson

Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.

26240

nodejs-best-practices

davila7

Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.

28120

workflow-orchestration-patterns

wshobson

Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration.

10117

Search skills

Search the agent skills registry