name: architecture description: sfdx-hardis project architecture, technology stack, provider pattern, configuration system, and project structure. Use when working with project structure, providers, hooks, or config. user-invocable: false
Architecture
Technology Stack
- Language: TypeScript (strict mode)
- CLI Framework: Oclif (Salesforce CLI framework)
- Build System: Wireit (task orchestration)
- Testing: Mocha with Nyc for coverage
- Linting: ESLint with Salesforce configurations
- AI Integration: LangChain (Anthropic, Google GenAI, Ollama, OpenAI) + Codex + Agentforce
Project Structure
src/
├── commands/hardis/ # CLI commands (~300+) organized by domain
│ ├── auth/ ├── cache/ ├── config/
│ ├── datacloud/ ├── doc/ ├── git/
│ ├── lint/ ├── mdapi/ ├── misc/
│ ├── org/ ├── package/ ├── packagexml/
│ ├── project/ ├── scratch/ ├── source/
│ └── work/
├── common/
│ ├── aiProvider/ # AI integration and prompt templates
│ └── utils/ # Shared utilities (barrel-exported from index.ts)
├── hooks/ # Oclif lifecycle hooks
├── i18n/ # Translation files (9 locales)
test/ # Test files (*.test.ts, *.nut.ts)
lib/ # Compiled JavaScript output
messages/ # Oclif message files (.md)
defaults/ # Default configurations and templates
docs/ # Project documentation
CLI Framework
- Commands extend
SfCommand<any>from@salesforce/sf-plugins-core. - Invoked as
sf hardis <topic> <action>. - ESM module (
"type": "module").
Headless / Agent Mode
When possible, every command should support a --agent boolean flag so it can be called non-interactively by AI agents and automation pipelines:
// Flag declaration
agent: Flags.boolean({
default: false,
description: 'Run in non-interactive mode for agents and automation',
}),
// In run()
const agentMode = flags.agent === true;
// Guard every interactive prompt
if (!isCI && !agentMode) {
const answer = await prompts({ ... });
}
- Add
'$ sf hardis:<topic>:<action> --agent'to the commandexamplesarray. - In agent mode the command must complete without blocking on any interactive prompt, applying sensible defaults instead.
Provider Pattern (src/common/)
External integrations use a root class + concrete implementations:
- gitProvider: GitHub, GitLab, Azure DevOps, Bitbucket
- notifProvider: Slack, MS Teams, Email, API webhook. Slack and Teams share the logical
messagingchannel; each provider declares its channel viagetChannel(). Routing is filtered per notification type and per channel via severity thresholds. See themonitoring-notificationsskill. - ticketProvider: Jira, Azure Boards, generic
- aiProvider: LangChain-based (Anthropic, Google GenAI, Ollama, OpenAI) + Codex + Agentforce
- actionsProvider: Post-deploy actions (Apex, data, manual, community publish, schedule batch)
- keyValueProviders: Salesforce org, local test
- docBuilder: Documentation generation
Monitoring Pipeline (src/common/monitoring/, src/common/notifProvider/)
hardis:org:monitor:all runs a list of sub-commands (monitoringCommandsDefault) on a configurable cadence. Each sub-command posts notifications through NotifProvider.postNotifications, which fans out to enabled channels (messaging / email / api) using per-notification-type severity thresholds. Defaults live in source; users override per-entry via the monitoringCommands property in .sfdx-hardis.yml, merged by key. The hardis:config:monitoring-defaults command exposes the full defaults payload to the VS Code extension UI.
When adding a monitoring command, a notification type, or changing default routing, use the monitoring-notifications skill -- it lists exactly which files to touch.
Configuration System (src/config/index.ts)
Three-Layer Config
Configuration uses a three-layer merge with priority: user > branch > project.
| Layer | File locations | Purpose |
|---|---|---|
| Project (global) | config/.sfdx-hardis.yml or config/.sfdx-hardis.yaml (also .sfdx-hardis.yaml/.yml at repo root, or package.json) |
Shared settings for the entire project, committed to git |
| Branch | config/branches/.sfdx-hardis.<branch-name>.yml |
Per-branch overrides (e.g., different target org, deploy options per environment). Branch name is auto-detected from git or CONFIG_BRANCH env var |
| User | config/user/.sfdx-hardis.<os-username>.yml |
Per-developer overrides, typically git-ignored |
Higher-priority layers override lower ones via Object.assign() (shallow merge).
Config File Discovery
Uses cosmiconfig to search for config files. Supported names: .sfdx-hardis.yaml, .sfdx-hardis.yml, and package.json (for project layer).
Remote Config Inheritance
A config file can include an extends property pointing to a remote YAML URL. The remote config is fetched and merged underneath the local config (local wins). This allows sharing a common config base across multiple projects.
# config/.sfdx-hardis.yml
extends: https://raw.githubusercontent.com/mycompany/shared-config/main/.sfdx-hardis.yml
projectName: my-project
API
getConfig(layer)- returns merged config up to the specified layer ("project","branch", or"user"- default"user")setConfig(layer, propValues)- writes properties to the config file for the specified layerCONSTANTS- static constants (API version, URLs, metadata type lists)getEnvVar(name)- reads env var with Azure unresolved-variable detection
JSON Schema
All config properties are defined in config/sfdx-hardis.jsonschema.json (JSON Schema draft-07). This schema is used to:
- Generate HTML documentation (
yarn buildrunsgenerate-schema-doc) - Validate config structure
- Power IDE autocompletion
When adding or modifying a config property, always update config/sfdx-hardis.jsonschema.json to keep it in sync. Each property should have $id, description, title, type, and optionally default, enum, examples, and docUrl.
Hooks (src/hooks/)
Oclif lifecycle hooks:
init: logging, upgrade check, websocket clientprerun: auth, dependency checkauth: authenticationpostrun: cache storefinally: notifications
WebSocket Client (src/common/websocketClient.ts)
Communicates with VS Code extension (vscode-sfdx-hardis) for UI interactions, progress, and prompts.
Utilities (src/common/utils/)
Barrel-exported from src/common/utils/index.ts:
uxLog()- loggingexecSfdxJson()- CLI subprocess calls- Deploy, git, org, XML utilities
AI Prompt Templates
Located in src/common/aiProvider/promptTemplates/. Each exports a PromptTemplateDefinition with variables and multilingual text. Users can override by placing .md files in config/prompt-templates/ (.txt also supported for backward compatibility).