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.zipInstalls 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.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
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/, andshared/.- A domain area may import peer domain areas,
config/, andshared/— nevercommands/. config/may importshared/only.src/shared/is a leaf — it imports no domain area and nocommands/(type-only@/configimports are allowed).allow-writeandenvwere moved intopolicy/;content/must not importpublishing/. Those two boundaries killed the formershared↔policyandcontent↔publishingcycles.tests/unit/architecture/module-boundaries.test.tsenforces those two invariants. It is not a full cycle detector — peer domain areas may still cross-import; the hard rule is thatshared/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
CODEfor 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 checklogger.isJson()before starting anorainstance.--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
keytarinsrc/serialization/tasks/env/deploy-token.ts(and similar for OAuth tokens) under thesitecoreai-cliservice. - Never write a token to
sitecoreai.cli.jsondirectly. TheaccessToken/deployTokenfields 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: falseon environments — destructive operations require explicit--allow-writeorallowWrite: truein config - Honor
--what-ifon push-style operations (preview without applying) --jsonoutput is structured + machine-parseable; never include decorative text in JSON-mode output. Wrap your output inbuildScaiEnvelope()from@/shared/envelopeso consumers can branch ondataregardless of which task produced the output. The canonical shape is{ command, environment, data, count?, whatIf?, summary?, meta? }— seesrc/shared/envelope.ts. Directprocess.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:
-
Library gate —
ensureAllowWrite(root, envName, override?)insrc/shared/allow-write.ts. Called from every destructive runner. ThrowsINPUT_INVALIDunlessenv.allowWriteor the per-calloverride(typically--allow-write) is set. -
MCP boundary gate —
ensureMcpElevationAllowed(root, envName), same module. Called from every MCP write tool's handler before the library runner. ThrowsAUTH_DENIEDif the env hasdenyMcpElevation: 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)(orensureAllowWritedirectly) at the start, afterwhatIfis checked. - Default
whatIf: trueon 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. Thetests/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
| Command | What it runs | When to use |
|---|---|---|
pnpm check | format:check + lint + typecheck + test | Before finishing a session |
pnpm test | Vitest unit tests | While coding |
pnpm test:integration | Integration tests (gated by SITECOREAI_RUN_INTEGRATION=1) | After touching API/auth/config |
pnpm smoke | build + spawn CLI smoke checks | Sanity check before publish |
pnpm lint:fix | ESLint with --fix | After bigger refactors |
pnpm format | Prettier write | Before 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=falseorDO_NOT_TRACK=1
When adding a command
- Define the parser in
src/commands/<group>/<name>.ts - Implement the task runner in
src/<group>/tasks/<name>.ts(orserialization/tasks/...) - Use
toLogger(options)for all output; honor--json - Throw via
createCliErrorwith ahint - Add a unit test in
tests/unit/...mirroring the source path - If the command hits a real Sitecore API, add an integration test in
tests/integration/ - If the command writes tokens or sensitive data, double-check no log path leaks them
- Regenerate the command reference:
pnpm docs:commands(writesdocs/commands.md) - 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. Startingorawhile 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
CODEonce it's shipped — telemetry and tooling depend on it. - **The
__Standard valueschicken-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.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| codebase-conventions (this skill) | 0 | 13d | No flags | Intermediate |
| senior-fullstack | 35 | 7mo | Review | Intermediate |
| mcp-builder | 136 | 3mo | Review | Advanced |
| architecture-patterns | 55 | 2mo | No flags | Advanced |
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.
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).
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.
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.
nodejs-best-practices
davila7
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.
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.