acek-skills 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -7
- package/agents/sf-admin.md +18 -0
- package/agents/sf-ba.md +16 -0
- package/agents/sf-data-migration.md +18 -0
- package/agents/sf-dev.md +18 -0
- package/agents/sf-devops.md +18 -0
- package/agents/sf-ideation.md +18 -0
- package/agents/sf-security-review.md +19 -0
- package/agents/sf-testing.md +18 -0
- package/bin/cli.js +66 -1
- package/package.json +3 -2
- package/skills/sf-admin/SKILL.md +11 -0
- package/skills/sf-architect/SKILL.md +102 -49
- package/skills/sf-ba/SKILL.md +11 -3
- package/skills/sf-data-migration/SKILL.md +11 -0
- package/skills/sf-dev/SKILL.md +17 -6
- package/skills/sf-devops/SKILL.md +11 -0
- package/skills/sf-ideation/SKILL.md +20 -9
- package/skills/sf-security-review/SKILL.md +11 -0
- package/skills/sf-testing/SKILL.md +58 -45
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Admin • Development • Testing • DevOps • Security Review • Data Migrat
|
|
|
23
23
|
- [Non-interactive install](#non-interactive-install)
|
|
24
24
|
- [Org alias templating](#org-alias-templating)
|
|
25
25
|
- [Install targets](#install-targets)
|
|
26
|
+
- [Sub-agents](#sub-agents)
|
|
26
27
|
- [Skills reference](#skills-reference)
|
|
27
28
|
- [CLI reference](#cli-reference)
|
|
28
29
|
- [Project structure](#project-structure)
|
|
@@ -83,7 +84,11 @@ Running `install` with no arguments walks you through three prompts:
|
|
|
83
84
|
converted into that tool's native rule format.
|
|
84
85
|
3. **Org aliases** — only asked if one of the selected skills references them (currently
|
|
85
86
|
`sf-devops` and `sf-data-migration`). Leave blank to fill in later by hand.
|
|
86
|
-
4. **
|
|
87
|
+
4. **Sub-agents** — any selected skill that has a matching sub-agent (same technical id, e.g.
|
|
88
|
+
`sf-dev`) installs it automatically to `.claude/agents/` on Claude Code targets — no separate
|
|
89
|
+
prompt. See [Sub-agents](#sub-agents). Not installed for Cursor/Windsurf/Copilot targets, which
|
|
90
|
+
have no subagent concept.
|
|
91
|
+
5. **Commands** — if `sf-architect` is selected and at least one Claude Code target is chosen, its
|
|
87
92
|
companion `/sf-init` slash command installs automatically to `.claude/commands/` — no separate
|
|
88
93
|
prompt. Not installed for Cursor/Windsurf/Copilot targets, which have no slash-command concept.
|
|
89
94
|
|
|
@@ -139,6 +144,36 @@ Cursor and Windsurf approximate it with their own rule-matching; Copilot's custo
|
|
|
139
144
|
apply more broadly since it has no equivalent trigger mechanism. Check each tool's docs if the
|
|
140
145
|
matching behavior matters for your workflow.
|
|
141
146
|
|
|
147
|
+
## Sub-agents
|
|
148
|
+
|
|
149
|
+
`sf-architect` acts as Salesforce's plan-mode orchestrator: once a plan is approved, it dispatches
|
|
150
|
+
each task to the owner skill's own sub-agent (Claude Code's native `Agent` tool, `subagent_type:
|
|
151
|
+
sf-[owner skill]`) instead of following that skill's conventions itself. Every owner skill has a
|
|
152
|
+
matching sub-agent under `agents/`, same technical id as its skill folder, each with a **fixed**
|
|
153
|
+
narrated persona:
|
|
154
|
+
|
|
155
|
+
| Owner skill (`subagent_type`) | Persona |
|
|
156
|
+
| ------------------------------ | --------------- |
|
|
157
|
+
| `sf-admin` | Eva Lovia |
|
|
158
|
+
| `sf-dev` | Comatozze |
|
|
159
|
+
| `sf-testing` | Riley Reid |
|
|
160
|
+
| `sf-devops` | Channel Preston |
|
|
161
|
+
| `sf-security-review` | Madison Ivy |
|
|
162
|
+
| `sf-data-migration` | Britney Amber |
|
|
163
|
+
| `sf-ba` | Isla Summer |
|
|
164
|
+
| `sf-ideation` | Asa Akira |
|
|
165
|
+
|
|
166
|
+
`sf-architect` itself narrates as **Ashley Fires** and is never dispatched as a sub-agent of
|
|
167
|
+
itself — it only ever assigns work out. Personas are narration only (a response signature line);
|
|
168
|
+
they never appear inside generated file content (PRDs, code, commit messages) except as a tracking
|
|
169
|
+
label in the Architecture Plan's Execution Log.
|
|
170
|
+
|
|
171
|
+
Installing a skill that has a matching sub-agent installs both automatically, to
|
|
172
|
+
`.claude/agents/<name>.md` — Claude Code targets only, since Cursor/Windsurf/Copilot have no
|
|
173
|
+
subagent equivalent (same rule as `/sf-init`, see [Install targets](#install-targets)). A skill's
|
|
174
|
+
sub-agent works standalone too — dispatch it directly with the `Agent` tool — but it's designed to
|
|
175
|
+
be driven by `sf-architect`'s plan-mode flow.
|
|
176
|
+
|
|
142
177
|
## Skills reference
|
|
143
178
|
|
|
144
179
|
<details>
|
|
@@ -148,10 +183,10 @@ Salesforce's plan mode. Gates all work behind an approved Architecture Plan befo
|
|
|
148
183
|
metadata is touched: runs Discovery (project scan + choice-based clarifying questions, never open
|
|
149
184
|
text), proposes Decisions with trade-offs for data model / automation layer / integration pattern
|
|
150
185
|
/ security model / Permission Set strategy, then breaks approved work into tasks dispatched to the
|
|
151
|
-
right skill (`sf-admin`, `sf-dev`, `sf-testing`, `sf-devops`,
|
|
152
|
-
`sf-data-migration`
|
|
153
|
-
PII-bearing object/field, an integration, or a
|
|
154
|
-
`instructions/architecture/` and are resumable across
|
|
186
|
+
right owner skill's **sub-agent** (`sf-admin`, `sf-dev`, `sf-testing`, `sf-devops`,
|
|
187
|
+
`sf-security-review`, `sf-data-migration` — see [Sub-agents](#sub-agents)) — always including a
|
|
188
|
+
`sf-security-review` task when the plan touches a PII-bearing object/field, an integration, or a
|
|
189
|
+
sharing/OWD change. Plans are saved to `instructions/architecture/` and are resumable across
|
|
155
190
|
sessions without re-scanning the project or re-reading chat history. Complements — does not
|
|
156
191
|
replace — `sf-ba` (PRDs) and `sf-ideation` (open-ended brainstorming), and can consume either as
|
|
157
192
|
input.
|
|
@@ -260,9 +295,13 @@ lives in its `SKILL.md`.
|
|
|
260
295
|
acek-skills install Interactive: pick skills, target IDE(s)/tool(s), and org aliases
|
|
261
296
|
acek-skills install --all Install all skills to Claude Code (project), no prompts
|
|
262
297
|
acek-skills install <name> Install a single skill to Claude Code (project), no prompts
|
|
263
|
-
acek-skills list List available skills and
|
|
298
|
+
acek-skills list List available skills, commands, and sub-agents
|
|
264
299
|
```
|
|
265
300
|
|
|
301
|
+
Any installed skill with a matching **sub-agent** (`.claude/agents/<name>.md`) installs it
|
|
302
|
+
automatically alongside it — Claude Code targets only, since Cursor/Windsurf/Copilot have no
|
|
303
|
+
subagent equivalent. See [Sub-agents](#sub-agents).
|
|
304
|
+
|
|
266
305
|
Installing `sf-architect` also installs its companion **`/sf-init`** slash command — Claude Code
|
|
267
306
|
targets only (`.claude/commands/`), since Cursor/Windsurf/Copilot have no slash-command
|
|
268
307
|
equivalent. Run `/sf-init` once per project after installing to bootstrap `architecture.md`;
|
|
@@ -283,6 +322,15 @@ skills/
|
|
|
283
322
|
sf-ideation/SKILL.md
|
|
284
323
|
sf-security-review/SKILL.md
|
|
285
324
|
sf-testing/SKILL.md
|
|
325
|
+
agents/
|
|
326
|
+
sf-admin.md sub-agent dispatched by sf-architect (subagent_type: sf-admin) — Claude Code only
|
|
327
|
+
sf-ba.md
|
|
328
|
+
sf-data-migration.md
|
|
329
|
+
sf-dev.md
|
|
330
|
+
sf-devops.md
|
|
331
|
+
sf-ideation.md
|
|
332
|
+
sf-security-review.md
|
|
333
|
+
sf-testing.md
|
|
286
334
|
commands/
|
|
287
335
|
sf-init.md /sf-init slash command — companion to sf-architect, Claude Code only
|
|
288
336
|
bin/
|
|
@@ -306,6 +354,10 @@ bin/
|
|
|
306
354
|
2. No CLI changes needed — `list` and `install` pick up any folder under `skills/` automatically.
|
|
307
355
|
3. If the skill needs org-specific values, use the `{{PROD_ORG_ALIAS}}` / `{{DEV_ORG_ALIAS}}`
|
|
308
356
|
placeholders (see [Org alias templating](#org-alias-templating)) rather than hardcoding one.
|
|
357
|
+
4. Optional: to make the skill dispatchable as one of `sf-architect`'s sub-agents, add
|
|
358
|
+
`agents/<name>.md` with the same technical id as the skill folder — see [Sub-agents](#sub-agents)
|
|
359
|
+
for the frontmatter shape and persona convention. Also no CLI changes needed; `install` matches
|
|
360
|
+
agent files to skill names by filename.
|
|
309
361
|
|
|
310
362
|
## FAQ
|
|
311
363
|
|
|
@@ -317,9 +369,15 @@ responds, and doesn't touch any org, sandbox, or production data on its own.
|
|
|
317
369
|
Yes — deselect any skill in the interactive wizard, or use `install <name>` for a single one.
|
|
318
370
|
|
|
319
371
|
**Can I re-run install to update after a new version is published?**
|
|
320
|
-
Yes, `npx` always resolves the latest version unless you pin one (`npx acek-skills@1.
|
|
372
|
+
Yes, `npx` always resolves the latest version unless you pin one (`npx acek-skills@1.4.0 install`).
|
|
321
373
|
Re-running overwrites previously installed files for the skills/targets you select.
|
|
322
374
|
|
|
375
|
+
**What are the sub-agents in `.claude/agents/`?**
|
|
376
|
+
Dispatch targets for `sf-architect`'s plan-mode execution — one per owner skill, invoked via
|
|
377
|
+
Claude Code's `Agent` tool (`subagent_type: sf-[owner skill]`) instead of `sf-architect` following
|
|
378
|
+
that skill's conventions itself. See [Sub-agents](#sub-agents). Only installed for Claude Code
|
|
379
|
+
targets; Cursor/Windsurf/Copilot have no subagent concept.
|
|
380
|
+
|
|
323
381
|
**Why do only Claude Code skills auto-trigger?**
|
|
324
382
|
Claude Code has a native skill system that matches tasks against each skill's `description`
|
|
325
383
|
frontmatter. Cursor, Windsurf, and Copilot don't expose the same mechanism, so their versions are
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-admin
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce administrator sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-admin`. Handles declarative configuration: custom objects/fields, page layouts, record
|
|
6
|
+
types, profiles, permission sets, sharing rules, validation rules, and flows.
|
|
7
|
+
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-admin`'s Persona section, then
|
|
12
|
+
load and strictly follow the `sf-admin` skill for every convention, checklist, and pattern in
|
|
13
|
+
this task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, exact files in
|
|
16
|
+
`Touches`, and any relevant Architecture Plan decisions). Report back a concise summary of what
|
|
17
|
+
changed and where. Do not write to the plan file — only the orchestrator writes status/log
|
|
18
|
+
updates.
|
package/agents/sf-ba.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-ba
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce business analyst sub-agent — dispatched by sf-architect for tasks whose Owner Skill
|
|
5
|
+
is `sf-ba`. Handles PRDs, user stories, feature specs, and functional requirement documents.
|
|
6
|
+
tools: Read, Write, Edit, Grep, Glob
|
|
7
|
+
model: inherit
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Open your response with the persona signature line defined in `sf-ba`'s Persona section, then
|
|
11
|
+
load and strictly follow the `sf-ba` skill for every convention and document structure it
|
|
12
|
+
defines — do not improvise anything that skill already defines.
|
|
13
|
+
|
|
14
|
+
The dispatch prompt supplies task-specific details (task ID, description, and any relevant
|
|
15
|
+
Architecture Plan context). Report back a concise summary of what document was written and
|
|
16
|
+
where. Do not write to the plan file — only the orchestrator writes status/log updates.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-data-migration
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce data migration sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-data-migration`. Handles bulk import/export strategy, upsert scripts with External IDs, and
|
|
6
|
+
data cleansing.
|
|
7
|
+
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-data-migration`'s Persona
|
|
12
|
+
section, then load and strictly follow the `sf-data-migration` skill for every convention,
|
|
13
|
+
checklist, and pattern in this task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, exact files in
|
|
16
|
+
`Touches`, and any relevant Architecture Plan decisions, including resolved org aliases). Report
|
|
17
|
+
back a concise summary of what changed and where. Do not write to the plan file — only the
|
|
18
|
+
orchestrator writes status/log updates.
|
package/agents/sf-dev.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-dev
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce developer sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-dev`. Handles custom development: Apex classes/triggers/batch jobs, LWC/Aura components,
|
|
6
|
+
SOQL, and integration/callout code.
|
|
7
|
+
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-dev`'s Persona section, then
|
|
12
|
+
load and strictly follow the `sf-dev` skill for every convention, checklist, and pattern in this
|
|
13
|
+
task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, exact files in
|
|
16
|
+
`Touches`, and any relevant Architecture Plan decisions). Report back a concise summary of what
|
|
17
|
+
changed and where. Do not write to the plan file — only the orchestrator writes status/log
|
|
18
|
+
updates.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-devops
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce DevOps sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-devops`. Handles deployment manifests, dry-run validation, Change Requests, and
|
|
6
|
+
sandbox-to-production deploys via SF CLI.
|
|
7
|
+
tools: Read, Write, Grep, Glob, Bash
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-devops`'s Persona section, then
|
|
12
|
+
load and strictly follow the `sf-devops` skill for every convention, checklist, and pattern in
|
|
13
|
+
this task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, exact files in
|
|
16
|
+
`Touches`, and any relevant Architecture Plan decisions, including resolved org aliases). Report
|
|
17
|
+
back a concise summary of what changed and where. Do not write to the plan file — only the
|
|
18
|
+
orchestrator writes status/log updates.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-ideation
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce ideation sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-ideation`. Generates anchored enhancement ideas for an existing Apex class, LWC component,
|
|
6
|
+
or closed/approved PRD.
|
|
7
|
+
tools: Read, Grep, Glob, Write
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-ideation`'s Persona section,
|
|
12
|
+
then load and strictly follow the `sf-ideation` skill's anchor requirement and idea-generation
|
|
13
|
+
pattern — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, and the anchor
|
|
16
|
+
file/component/PRD to ground ideas in). Report back a concise summary of the ideas produced and
|
|
17
|
+
where they were written. Do not write to the plan file — only the orchestrator writes status/log
|
|
18
|
+
updates.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-security-review
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce security review sub-agent — dispatched by sf-architect for tasks whose Owner Skill
|
|
5
|
+
is `sf-security-review`. Handles CRUD/FLS audits, sharing model review, PII/data-privacy
|
|
6
|
+
checks, and production sign-off.
|
|
7
|
+
tools: Read, Grep, Glob
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-security-review`'s Persona
|
|
12
|
+
section, then load and strictly follow the `sf-security-review` skill for every convention,
|
|
13
|
+
checklist, and pattern in this task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
This agent is read-only by design — it audits and reports, it never edits code or metadata
|
|
16
|
+
itself. The dispatch prompt supplies task-specific details (task ID, description, exact
|
|
17
|
+
files/components to review, and any relevant Architecture Plan decisions). Report back findings
|
|
18
|
+
and a sign-off status. Do not write to the plan file — only the orchestrator writes status/log
|
|
19
|
+
updates.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-testing
|
|
3
|
+
description: >
|
|
4
|
+
Salesforce testing sub-agent — dispatched by sf-architect for tasks whose Owner Skill is
|
|
5
|
+
`sf-testing`. Handles Apex test classes, TestDataFactory, callout/platform-event mocking, and
|
|
6
|
+
LWC Jest unit tests.
|
|
7
|
+
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Open your response with the persona signature line defined in `sf-testing`'s Persona section,
|
|
12
|
+
then load and strictly follow the `sf-testing` skill for every convention, checklist, and pattern
|
|
13
|
+
in this task — do not improvise anything that skill already defines.
|
|
14
|
+
|
|
15
|
+
The dispatch prompt supplies task-specific details (task ID, description, exact files in
|
|
16
|
+
`Touches`, and any relevant Architecture Plan decisions). Report back a concise summary of what
|
|
17
|
+
changed and where. Do not write to the plan file — only the orchestrator writes status/log
|
|
18
|
+
updates.
|
package/bin/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const target = args[1]; // optional: specific skill name, or "--all"
|
|
|
10
10
|
|
|
11
11
|
const SKILLS_SRC = path.join(__dirname, '../skills');
|
|
12
12
|
const COMMANDS_SRC = path.join(__dirname, '../commands');
|
|
13
|
+
const AGENTS_SRC = path.join(__dirname, '../agents');
|
|
13
14
|
|
|
14
15
|
function printBanner() {
|
|
15
16
|
console.log(`\x1b[36m
|
|
@@ -28,6 +29,7 @@ const TARGETS = {
|
|
|
28
29
|
label: 'Claude Code — project (./.claude/skills)',
|
|
29
30
|
dir: (cwd) => path.join(cwd, '.claude/skills'),
|
|
30
31
|
commandsDir: (cwd) => path.join(cwd, '.claude/commands'),
|
|
32
|
+
agentDir: (cwd) => path.join(cwd, '.claude/agents'),
|
|
31
33
|
format: 'claude',
|
|
32
34
|
selected: true,
|
|
33
35
|
},
|
|
@@ -35,6 +37,7 @@ const TARGETS = {
|
|
|
35
37
|
label: 'Claude Code — global (~/.claude/skills)',
|
|
36
38
|
dir: () => path.join(os.homedir(), '.claude/skills'),
|
|
37
39
|
commandsDir: () => path.join(os.homedir(), '.claude/commands'),
|
|
40
|
+
agentDir: () => path.join(os.homedir(), '.claude/agents'),
|
|
38
41
|
format: 'claude',
|
|
39
42
|
selected: false,
|
|
40
43
|
},
|
|
@@ -122,6 +125,30 @@ function installCommandToTarget(commandName, targetKey, cwd, aliases = {}) {
|
|
|
122
125
|
fs.writeFileSync(path.join(destDir, `${commandName}.md`), content);
|
|
123
126
|
}
|
|
124
127
|
|
|
128
|
+
// Sub-agents (.claude/agents/*.md) are dispatched by sf-architect via the
|
|
129
|
+
// Agent tool (subagent_type: sf-<skill>) — one per owner skill, same
|
|
130
|
+
// technical id as the matching skill folder. Like commands, they're a
|
|
131
|
+
// Claude-Code-only concept: Cursor/Windsurf/Copilot have no subagent
|
|
132
|
+
// equivalent, so they only ever install to 'claude' format targets.
|
|
133
|
+
function listAgents() {
|
|
134
|
+
if (!fs.existsSync(AGENTS_SRC)) return [];
|
|
135
|
+
return fs
|
|
136
|
+
.readdirSync(AGENTS_SRC, { withFileTypes: true })
|
|
137
|
+
.filter((e) => e.isFile() && e.name.endsWith('.md'))
|
|
138
|
+
.map((e) => e.name.replace(/\.md$/, ''));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function installAgentToTarget(agentName, targetKey, cwd) {
|
|
142
|
+
const targetDef = TARGETS[targetKey];
|
|
143
|
+
if (targetDef.format !== 'claude' || !targetDef.agentDir) return;
|
|
144
|
+
const destDir = targetDef.agentDir(cwd);
|
|
145
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
146
|
+
fs.copyFileSync(
|
|
147
|
+
path.join(AGENTS_SRC, `${agentName}.md`),
|
|
148
|
+
path.join(destDir, `${agentName}.md`),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
125
152
|
// Pulls `name`/`description` out of the SKILL.md frontmatter (YAML folded
|
|
126
153
|
// scalar style: "description: >") so non-Claude formats can reuse them.
|
|
127
154
|
function parseSkill(skillName) {
|
|
@@ -299,6 +326,7 @@ async function runInteractiveInstall() {
|
|
|
299
326
|
);
|
|
300
327
|
}
|
|
301
328
|
|
|
329
|
+
const availableAgents = listAgents();
|
|
302
330
|
const cwd = process.cwd();
|
|
303
331
|
for (const targetKey of targets) {
|
|
304
332
|
for (const skillName of skills) {
|
|
@@ -308,6 +336,16 @@ async function runInteractiveInstall() {
|
|
|
308
336
|
`✅ ${skills.length} skill(s) installed to ${TARGETS[targetKey].label}`,
|
|
309
337
|
);
|
|
310
338
|
|
|
339
|
+
const agentsToInstall = skills.filter((s) => availableAgents.includes(s));
|
|
340
|
+
if (agentsToInstall.length > 0 && TARGETS[targetKey].agentDir) {
|
|
341
|
+
for (const agentName of agentsToInstall) {
|
|
342
|
+
installAgentToTarget(agentName, targetKey, cwd);
|
|
343
|
+
}
|
|
344
|
+
console.log(
|
|
345
|
+
`✅ ${agentsToInstall.length} sub-agent(s) installed to ${TARGETS[targetKey].label}`,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
311
349
|
if (skills.includes('sf-architect') && TARGETS[targetKey].commandsDir) {
|
|
312
350
|
installCommandToTarget('sf-init', targetKey, cwd, aliases);
|
|
313
351
|
console.log(
|
|
@@ -340,6 +378,17 @@ async function main() {
|
|
|
340
378
|
console.log(
|
|
341
379
|
`✅ All ${available.length} skill(s) installed to ${TARGETS['claude-project'].label}`,
|
|
342
380
|
);
|
|
381
|
+
const agentsToInstall = listAgents().filter((a) =>
|
|
382
|
+
available.includes(a),
|
|
383
|
+
);
|
|
384
|
+
for (const agentName of agentsToInstall) {
|
|
385
|
+
installAgentToTarget(agentName, 'claude-project', process.cwd());
|
|
386
|
+
}
|
|
387
|
+
if (agentsToInstall.length > 0) {
|
|
388
|
+
console.log(
|
|
389
|
+
`✅ ${agentsToInstall.length} sub-agent(s) installed to ${TARGETS['claude-project'].label}`,
|
|
390
|
+
);
|
|
391
|
+
}
|
|
343
392
|
if (available.includes('sf-architect')) {
|
|
344
393
|
installCommandToTarget(
|
|
345
394
|
'sf-init',
|
|
@@ -370,6 +419,12 @@ async function main() {
|
|
|
370
419
|
console.log(
|
|
371
420
|
`✅ Installed skill: ${target} → ${TARGETS['claude-project'].label}`,
|
|
372
421
|
);
|
|
422
|
+
if (listAgents().includes(target)) {
|
|
423
|
+
installAgentToTarget(target, 'claude-project', process.cwd());
|
|
424
|
+
console.log(
|
|
425
|
+
`✅ Installed sub-agent: ${target} → ${TARGETS['claude-project'].label}`,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
373
428
|
if (target === 'sf-architect') {
|
|
374
429
|
installCommandToTarget(
|
|
375
430
|
'sf-init',
|
|
@@ -397,6 +452,11 @@ async function main() {
|
|
|
397
452
|
console.log('\n⚡ Available commands:');
|
|
398
453
|
commands.forEach((c) => console.log(` - /${c}`));
|
|
399
454
|
}
|
|
455
|
+
const agents = listAgents();
|
|
456
|
+
if (agents.length > 0) {
|
|
457
|
+
console.log('\n🤖 Available sub-agents (dispatched by sf-architect):');
|
|
458
|
+
agents.forEach((a) => console.log(` - ${a}`));
|
|
459
|
+
}
|
|
400
460
|
} else {
|
|
401
461
|
console.log(`
|
|
402
462
|
Usage:
|
|
@@ -404,7 +464,12 @@ Usage:
|
|
|
404
464
|
acek-skills install --all Install all skills to Claude Code (project), no prompts
|
|
405
465
|
acek-skills install <name> Install a single skill to Claude Code (project), no prompts
|
|
406
466
|
|
|
407
|
-
acek-skills list List available skills and
|
|
467
|
+
acek-skills list List available skills, commands, and sub-agents
|
|
468
|
+
|
|
469
|
+
Each installed skill that has a matching sub-agent (same technical id, e.g. sf-dev) also installs
|
|
470
|
+
that sub-agent to .claude/agents/ (Claude Code targets only — Cursor/Windsurf/Copilot have no
|
|
471
|
+
subagent equivalent). sf-architect dispatches these during Phase 4 execution instead of following
|
|
472
|
+
their conventions itself.
|
|
408
473
|
|
|
409
474
|
Installing sf-architect also installs its companion /sf-init slash command (Claude Code targets
|
|
410
475
|
only — Cursor/Windsurf/Copilot have no slash-command equivalent). Run /sf-init once per project
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "acek-skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Installable Claude Code skills for Salesforce development (admin, dev, BA, testing, devops, security review, data migration, ideation)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"acek-skills": "bin/cli.js"
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"bin/",
|
|
10
10
|
"skills/",
|
|
11
|
-
"commands"
|
|
11
|
+
"commands",
|
|
12
|
+
"agents"
|
|
12
13
|
],
|
|
13
14
|
"keywords": [
|
|
14
15
|
"claude",
|
package/skills/sf-admin/SKILL.md
CHANGED
|
@@ -12,6 +12,17 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
# Salesforce Administrator Skill
|
|
14
14
|
|
|
15
|
+
## Persona
|
|
16
|
+
|
|
17
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
18
|
+
|
|
19
|
+
`— Eva Lovia, sf-admin`
|
|
20
|
+
|
|
21
|
+
This is narration only. Never include this name inside generated file content: not in PRDs, CRs,
|
|
22
|
+
metadata, code comments, or commit messages. The one existing exception is the Architecture Plan's
|
|
23
|
+
Execution Log (owned by `sf-architect`), which may reference it as a tracking label when this
|
|
24
|
+
skill is dispatched as a sub-agent task.
|
|
25
|
+
|
|
15
26
|
## Environment Context
|
|
16
27
|
|
|
17
28
|
- API Version: **not hardcoded** — new files inherit whatever `sourceApiVersion` is set in the
|
|
@@ -17,6 +17,18 @@ description: >
|
|
|
17
17
|
|
|
18
18
|
# Salesforce Architect Skill (sf-architect)
|
|
19
19
|
|
|
20
|
+
## Persona
|
|
21
|
+
|
|
22
|
+
When this skill runs, open the response with:
|
|
23
|
+
|
|
24
|
+
`— Ashley Fires, sf-architect`
|
|
25
|
+
|
|
26
|
+
This is narration only. Never include this name inside generated file content: not in PRDs, CRs,
|
|
27
|
+
Apex/LWC code, code comments, or commit messages. The one exception is the Architecture Plan's
|
|
28
|
+
Execution Log, which may reference dispatched sub-agents' own personas as tracking labels (see
|
|
29
|
+
[Sub-Agent Personas](#sub-agent-personas) in Phase 4) — Ashley Fires' own name does not appear
|
|
30
|
+
there since the orchestrator is never dispatched as a sub-agent of itself.
|
|
31
|
+
|
|
20
32
|
## Core Principle
|
|
21
33
|
|
|
22
34
|
sf-architect is Salesforce's plan mode. It never touches an org, writes code, or creates metadata
|
|
@@ -39,20 +51,25 @@ Three rules govern everything below:
|
|
|
39
51
|
## Relationship to Other Skills
|
|
40
52
|
|
|
41
53
|
sf-architect does not replace any existing skill — it decides, sequences, and dispatches to them.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
| `sf-
|
|
49
|
-
| `sf-
|
|
50
|
-
| `sf-
|
|
51
|
-
| `sf-
|
|
52
|
-
| `sf-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
Each of the 8 has a matching sub-agent (same technical id, e.g. `sf-dev`) that architect dispatches
|
|
55
|
+
via the `Agent` tool during Phase 4 — see [Sub-Agent Personas](#sub-agent-personas) below for the
|
|
56
|
+
fixed persona each one narrates under.
|
|
57
|
+
|
|
58
|
+
| Skill | Persona | sf-architect's relationship to it |
|
|
59
|
+
| -------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `sf-ideation` | Asa Akira | Optional **input**. If open-ended brainstorming already happened, architect can consume its output as a starting point. Architect itself does not brainstorm — it decides between already-surfaced options. |
|
|
61
|
+
| `sf-ba` | Isla Summer | Optional **input**. If a PRD exists (`instructions/prd/...`), architect reads it for business requirements. Architect does **not** write PRDs, user stories, or acceptance criteria — that stays sf-ba's job. The plan links to the PRD path rather than copying its content. |
|
|
62
|
+
| `sf-admin` | Eva Lovia | **Owner skill** for declarative tasks: objects, fields, flows, permission sets, validation rules, page layouts. |
|
|
63
|
+
| `sf-dev` | Comatozze | **Owner skill** for custom code tasks: Apex, LWC, triggers, integrations. |
|
|
64
|
+
| `sf-testing` | Riley Reid | **Owner skill** for test class tasks and coverage verification. |
|
|
65
|
+
| `sf-devops` | Channel Preston | **Owner skill** for deployment tasks: manifest, dry-run, CR, actual deploy. |
|
|
66
|
+
| `sf-security-review` | Madison Ivy | **Owner skill** for CRUD/FLS audits, sharing model review, production sign-off. |
|
|
67
|
+
| `sf-data-migration` | Britney Amber | **Owner skill** for bulk data load/migration tasks tied to the feature. |
|
|
68
|
+
|
|
69
|
+
When dispatching a task, sf-architect sends it to that owner skill's sub-agent (`subagent_type:
|
|
70
|
+
sf-[owner skill]`) rather than following the skill's conventions itself — the sub-agent loads its
|
|
71
|
+
own skill and signs its response with its persona. Architect never impersonates another skill's
|
|
72
|
+
persona.
|
|
56
73
|
|
|
57
74
|
---
|
|
58
75
|
|
|
@@ -198,26 +215,32 @@ dispatched to parallel subagents; tasks that depend on each other still run in s
|
|
|
198
215
|
two tasks owned by different skills, as long as their `Touches` don't overlap. Parallel
|
|
199
216
|
eligibility is decided by `Touches`, never by which skill owns the task.
|
|
200
217
|
3. **Dispatch the batch:**
|
|
201
|
-
- **
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
- **Every task, including a batch of 1, dispatches to its owner skill's sub-agent** via the
|
|
219
|
+
`Agent` tool with `subagent_type: sf-[owner skill]` (e.g. `subagent_type: sf-dev`) — the
|
|
220
|
+
orchestrator never executes another skill's conventions itself and never signs a response
|
|
221
|
+
with another skill's persona. A batch of 1 is just a single dispatch call, not a parallel
|
|
222
|
+
one — there's no "run it in the main thread instead" shortcut anymore, since the sub-agent
|
|
223
|
+
is what guarantees the right tools, model, and persona for that owner skill.
|
|
224
|
+
- **Batch of 2+** → dispatch each task's sub-agent in the same turn, one `Agent` call per task.
|
|
225
|
+
This holds even when two or more tasks in the batch share the same Owner Skill (e.g. two
|
|
226
|
+
`sf-dev` tasks) — each still gets its own `sf-dev` sub-agent invocation, invoked
|
|
227
|
+
independently; never route two tasks through one sub-agent call just because they share an
|
|
228
|
+
owner skill.
|
|
229
|
+
- **Each dispatch prompt states explicitly:** the task ID, description, and the exact file(s)
|
|
230
|
+
in `Touches`. Nothing about "follow this skill's conventions" needs to be said — the
|
|
231
|
+
sub-agent's own definition already loads its skill and signs its own persona; the
|
|
232
|
+
orchestrator only supplies the task-specific facts.
|
|
233
|
+
- **Sub-agent personas are fixed per owner skill, not randomly assigned** — see
|
|
234
|
+
[Sub-Agent Personas](#sub-agent-personas) below. When two tasks in the same batch share an
|
|
235
|
+
Owner Skill (same fixed persona), disambiguate every reference with the task ID, e.g.
|
|
236
|
+
"Dispatched to Comatozze (TASK-03)" and "Dispatched to Comatozze (TASK-04)."
|
|
214
237
|
4. **Only the orchestrator (main thread) writes to the plan file.** Subagents report their result
|
|
215
238
|
back; they never edit `instructions/architecture/*.md` directly. Once every subagent in the
|
|
216
239
|
batch has reported back, the orchestrator updates each task's status serially — this is what
|
|
217
240
|
prevents concurrent writes to the same plan file.
|
|
218
241
|
5. **Per task, on completion:** set status to `D` (Done) and append **one line** to the Execution
|
|
219
|
-
Log — no narrative, just what changed, where, and
|
|
220
|
-
|
|
242
|
+
Log — no narrative, just what changed, where, and which sub-agent persona handled it (see
|
|
243
|
+
[Sub-Agent Personas](#sub-agent-personas)).
|
|
221
244
|
6. **Per task, if it can't proceed** (missing decision, blocked dependency, discovered conflict):
|
|
222
245
|
set status to `B` (Blocked), write a one-line reason, and surface it to the user — a Blocked
|
|
223
246
|
task in a batch does not stop the other tasks in that same batch from completing.
|
|
@@ -226,9 +249,30 @@ dispatched to parallel subagents; tasks that depend on each other still run in s
|
|
|
226
249
|
remaining task is `B` — in which case stop and ask the user how to proceed via the choice
|
|
227
250
|
format.
|
|
228
251
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
252
|
+
#### Sub-Agent Personas
|
|
253
|
+
|
|
254
|
+
Every owner-skill sub-agent has one **fixed** persona — not a random pool. The persona is set by
|
|
255
|
+
the sub-agent's own skill file (see that skill's `## Persona` section) and is used consistently in
|
|
256
|
+
dispatch narration and Execution Log lines:
|
|
257
|
+
|
|
258
|
+
| Owner Skill (`subagent_type`) | Persona |
|
|
259
|
+
| ----------------------------- | --------------- |
|
|
260
|
+
| `sf-admin` | Eva Lovia |
|
|
261
|
+
| `sf-dev` | Comatozze |
|
|
262
|
+
| `sf-testing` | Riley Reid |
|
|
263
|
+
| `sf-devops` | Channel Preston |
|
|
264
|
+
| `sf-security-review` | Madison Ivy |
|
|
265
|
+
| `sf-data-migration` | Britney Amber |
|
|
266
|
+
| `sf-ba` | Isla Summer |
|
|
267
|
+
| `sf-ideation` | Asa Akira |
|
|
268
|
+
|
|
269
|
+
Because the persona is fixed per skill rather than random per batch, two tasks in the same batch
|
|
270
|
+
only collide when they share an Owner Skill (e.g. two `sf-dev` tasks are both "Comatozze"). In
|
|
271
|
+
that case, disambiguate every mention — narration and Execution Log alike — with the task ID:
|
|
272
|
+
"Comatozze (TASK-03)" and "Comatozze (TASK-04)," not two bare "Comatozze" entries.
|
|
273
|
+
|
|
274
|
+
Ashley Fires (sf-architect's own persona, see its `## Persona` section) never appears in this
|
|
275
|
+
table — the orchestrator is never dispatched as a sub-agent of itself.
|
|
232
276
|
|
|
233
277
|
### Phase 5 — Resume
|
|
234
278
|
|
|
@@ -328,22 +372,26 @@ Permission Set Group `[PSG Name]`
|
|
|
328
372
|
|
|
329
373
|
**Touches** is what makes parallel dispatch safe: TASK-02, TASK-03, and TASK-04 all depend only on
|
|
330
374
|
TASK-01 and touch different things — they're a valid parallel batch, dispatched as three separate
|
|
331
|
-
|
|
332
|
-
independent
|
|
333
|
-
skill owns the task.
|
|
334
|
-
|
|
375
|
+
sub-agent calls. Note TASK-03 and TASK-04 share the same Owner Skill (`sf-dev`) but still run as
|
|
376
|
+
two independent `sf-dev` sub-agent invocations in that batch — parallel eligibility is decided by
|
|
377
|
+
`Touches`, not by which skill owns the task. Since both share `sf-dev`'s fixed persona (Comatozze),
|
|
378
|
+
disambiguate them in narration/log as "Comatozze (TASK-03)" and "Comatozze (TASK-04)." TASK-05
|
|
379
|
+
depends on TASK-03 and must wait for it. TASK-06 depends on both TASK-04 and TASK-05, so it waits
|
|
380
|
+
for the slower of the two.
|
|
335
381
|
|
|
336
382
|
---
|
|
337
383
|
|
|
338
384
|
## Execution Log
|
|
339
385
|
|
|
340
|
-
_One line per completed or blocked task. No narrative.
|
|
341
|
-
|
|
386
|
+
_One line per completed or blocked task. No narrative. Always include the dispatched sub-agent's
|
|
387
|
+
persona — every task dispatches to its owner skill's sub-agent now, there's no solo/main-thread
|
|
388
|
+
execution to omit it for. Add the task ID after the persona whenever another task in the same
|
|
389
|
+
batch shares it (see [Sub-Agent Personas](#sub-agent-personas))._
|
|
342
390
|
|
|
343
|
-
- YYYY-MM-DD HH:MM — TASK-01 done — Created `Project__c` fields per Decision 1
|
|
344
|
-
- YYYY-MM-DD HH:MM — TASK-02 done (agent:
|
|
345
|
-
- YYYY-MM-DD HH:MM — TASK-03 done (agent:
|
|
346
|
-
- YYYY-MM-DD HH:MM — TASK-04 blocked (agent:
|
|
391
|
+
- YYYY-MM-DD HH:MM — TASK-01 done (agent: Eva Lovia) — Created `Project__c` fields per Decision 1
|
|
392
|
+
- YYYY-MM-DD HH:MM — TASK-02 done (agent: Eva Lovia) — Extended `Project Manager Access` PS
|
|
393
|
+
- YYYY-MM-DD HH:MM — TASK-03 done (agent: Comatozze (TASK-03)) — Added `getProjects()` to `ProjectController.cls`
|
|
394
|
+
- YYYY-MM-DD HH:MM — TASK-04 blocked (agent: Comatozze (TASK-04)) — needs Decision on empty-state copy, asked user
|
|
347
395
|
```
|
|
348
396
|
|
|
349
397
|
---
|
|
@@ -394,9 +442,11 @@ best if users need to review before submitting (D) Other — describe your own a
|
|
|
394
442
|
9. **Read `architecture.md` instead of re-scanning the whole project.** If the project baseline
|
|
395
443
|
exists (from `/sf-init`), it already has the tech stack, data model, Permission Set inventory,
|
|
396
444
|
and org aliases — reuse it. Only scan for what's specific to the current feature.
|
|
397
|
-
10. **
|
|
398
|
-
|
|
399
|
-
|
|
445
|
+
10. **Dispatch prompts stay minimal.** Every task — including a batch of 1 — dispatches to its
|
|
446
|
+
owner skill's sub-agent, so there's no main-thread shortcut to weigh trivial batches against
|
|
447
|
+
anymore. Keep the win on the prompt side instead: state only the task ID, description, and
|
|
448
|
+
`Touches` — the sub-agent's own definition already carries its skill and persona, so there's
|
|
449
|
+
nothing else to restate per dispatch.
|
|
400
450
|
|
|
401
451
|
---
|
|
402
452
|
|
|
@@ -406,8 +456,9 @@ best if users need to review before submitting (D) Other — describe your own a
|
|
|
406
456
|
- ✕ Asking an open-ended question when a choice-with-options would work
|
|
407
457
|
- ✕ Re-scanning the whole project on every resume
|
|
408
458
|
- ✕ Copying a PRD's full content into the plan file instead of linking it
|
|
409
|
-
- ✕
|
|
410
|
-
|
|
459
|
+
- ✕ The orchestrator executing an owner skill's task itself instead of dispatching it to that
|
|
460
|
+
skill's sub-agent (e.g. writing Apex directly rather than dispatching to `sf-dev`/Comatozze) —
|
|
461
|
+
this also means signing a response with another skill's persona, which architect never does
|
|
411
462
|
- ✕ Marking a task `D` without a corresponding Execution Log line
|
|
412
463
|
- ✕ Producing a "PRD" — that document belongs to sf-ba; sf-architect produces a plan
|
|
413
464
|
- ✕ Continuing to the next task when the current one is `B` (Blocked) without surfacing it first
|
|
@@ -420,11 +471,13 @@ best if users need to review before submitting (D) Other — describe your own a
|
|
|
420
471
|
`Touches` is too vague to be sure it doesn't
|
|
421
472
|
- ✕ Merging two or more same-Owner-Skill tasks into a single subagent because they'd trigger the
|
|
422
473
|
same skill — each task still gets its own subagent when their `Touches` don't overlap
|
|
423
|
-
- ✕ Treating parallel-safe dispatch as only available across
|
|
474
|
+
- ✕ Treating parallel-safe dispatch as only available across _different_ Owner Skills — two tasks
|
|
424
475
|
under the same skill (e.g. two `sf-dev` tasks) are equally eligible when `Touches` don't overlap
|
|
425
476
|
- ✕ Letting a subagent write directly to the plan file — only the orchestrator writes status/log
|
|
426
477
|
updates, and only after the batch reports back
|
|
427
|
-
- ✕
|
|
478
|
+
- ✕ Two same-Owner-Skill tasks in one batch logged under the same persona with no task-ID
|
|
479
|
+
disambiguation (e.g. two bare "Comatozze" lines instead of "Comatozze (TASK-03)" / "Comatozze
|
|
480
|
+
(TASK-04)")
|
|
428
481
|
- ✕ Treating an `IP` task found on resume as already finished — it means the batch was
|
|
429
482
|
interrupted, not that the work landed; re-verify before re-dispatching
|
|
430
483
|
- ✕ Asking the user to type an org alias from memory when `sf org list` can just be run
|
package/skills/sf-ba/SKILL.md
CHANGED
|
@@ -12,6 +12,17 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
# Salesforce Business Analyst Skill
|
|
14
14
|
|
|
15
|
+
## Persona
|
|
16
|
+
|
|
17
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
18
|
+
|
|
19
|
+
`— Isla Summer, sf-ba`
|
|
20
|
+
|
|
21
|
+
This is narration only. Never include this name inside generated file content: not in PRDs, specs,
|
|
22
|
+
or commit messages. The one existing exception is the Architecture Plan's Execution Log (owned by
|
|
23
|
+
`sf-architect`), which may reference it as a tracking label when this skill is dispatched as a
|
|
24
|
+
sub-agent task.
|
|
25
|
+
|
|
15
26
|
## Core Principle
|
|
16
27
|
|
|
17
28
|
BA documents bridge the gap between business intent and technical execution. Every document must be:
|
|
@@ -348,8 +359,6 @@ WHERE AccountId = :accountId AND ProjectStatus__c != 'Closed'
|
|
|
348
359
|
| ------------------- | ----------------------------------------------- |
|
|
349
360
|
| `ProjectHelperTest` | Happy path, no records, insufficient permission |
|
|
350
361
|
|
|
351
|
-
```
|
|
352
|
-
|
|
353
362
|
---
|
|
354
363
|
|
|
355
364
|
## BA Workflow
|
|
@@ -362,4 +371,3 @@ When asked to write BA documentation:
|
|
|
362
371
|
4. **Acceptance Criteria first** — if you can't write AC, the requirement isn't clear enough yet
|
|
363
372
|
5. **Flag open questions** — better to surface uncertainty than assume
|
|
364
373
|
6. **Always specify the implementor** — Admin, Dev, or Both for each requirement
|
|
365
|
-
```
|
|
@@ -12,6 +12,17 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
# Salesforce Data Migration Skill
|
|
14
14
|
|
|
15
|
+
## Persona
|
|
16
|
+
|
|
17
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
18
|
+
|
|
19
|
+
`— Britney Amber, sf-data-migration`
|
|
20
|
+
|
|
21
|
+
This is narration only. Never include this name inside generated file content: not in migration
|
|
22
|
+
plans, scripts, CRs, or commit messages. The one existing exception is the Architecture Plan's
|
|
23
|
+
Execution Log (owned by `sf-architect`), which may reference it as a tracking label when this
|
|
24
|
+
skill is dispatched as a sub-agent task.
|
|
25
|
+
|
|
15
26
|
## Environment Context
|
|
16
27
|
|
|
17
28
|
- API Version: **not hardcoded** — new files inherit whatever `sourceApiVersion` is set in the
|
package/skills/sf-dev/SKILL.md
CHANGED
|
@@ -11,6 +11,17 @@ description: >
|
|
|
11
11
|
|
|
12
12
|
# Salesforce Developer Skill
|
|
13
13
|
|
|
14
|
+
## Persona
|
|
15
|
+
|
|
16
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
17
|
+
|
|
18
|
+
`— Comatozze, sf-dev`
|
|
19
|
+
|
|
20
|
+
This is narration only. Never include this name inside generated file content: not in PRDs, CRs,
|
|
21
|
+
Apex/LWC code, code comments, or commit messages. The one existing exception is the Architecture
|
|
22
|
+
Plan's Execution Log (owned by `sf-architect`), which may reference it as a tracking label when
|
|
23
|
+
this skill is dispatched as a sub-agent task.
|
|
24
|
+
|
|
14
25
|
## Environment Context
|
|
15
26
|
|
|
16
27
|
- API Version: **not hardcoded** — new files inherit whatever `sourceApiVersion` is set in the
|
|
@@ -177,13 +188,13 @@ public static Result myMethod(String param) {
|
|
|
177
188
|
|
|
178
189
|
### Naming Conventions
|
|
179
190
|
|
|
180
|
-
| Type | Convention
|
|
181
|
-
| ------------ |
|
|
182
|
-
| Apex Class | PascalCase
|
|
183
|
-
| Test Class | PascalCase + `Test` suffix
|
|
191
|
+
| Type | Convention | Example |
|
|
192
|
+
| ------------ | --------------------------------- | -------------------------------------- |
|
|
193
|
+
| Apex Class | PascalCase | `AccountHelper`, `OpportunityService` |
|
|
194
|
+
| Test Class | PascalCase + `Test` suffix | `AccountHelperTest` |
|
|
184
195
|
| Apex Trigger | `<Object>Trigger`, one per object | `AccountTrigger`, `OpportunityTrigger` |
|
|
185
|
-
| Custom Field | PascalCase\_\_c
|
|
186
|
-
| Variable | camelCase
|
|
196
|
+
| Custom Field | PascalCase\_\_c | `ProjectStatus__c` |
|
|
197
|
+
| Variable | camelCase | `accountList`, `oppMap` |
|
|
187
198
|
|
|
188
199
|
### ApexDoc (required on all public methods)
|
|
189
200
|
|
|
@@ -12,6 +12,17 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
# Salesforce DevOps Skill
|
|
14
14
|
|
|
15
|
+
## Persona
|
|
16
|
+
|
|
17
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
18
|
+
|
|
19
|
+
`— Channel Preston, sf-devops`
|
|
20
|
+
|
|
21
|
+
This is narration only. Never include this name inside generated file content: not in manifests,
|
|
22
|
+
CRs, deploy docs, or commit messages. The one existing exception is the Architecture Plan's
|
|
23
|
+
Execution Log (owned by `sf-architect`), which may reference it as a tracking label when this
|
|
24
|
+
skill is dispatched as a sub-agent task.
|
|
25
|
+
|
|
15
26
|
## Environment Context
|
|
16
27
|
|
|
17
28
|
- API Version: **not hardcoded** — new files inherit whatever `sourceApiVersion` is set in the
|
|
@@ -14,6 +14,17 @@ description: >
|
|
|
14
14
|
|
|
15
15
|
# Salesforce Ideation Skill
|
|
16
16
|
|
|
17
|
+
## Persona
|
|
18
|
+
|
|
19
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
20
|
+
|
|
21
|
+
`— Asa Akira, sf-ideation`
|
|
22
|
+
|
|
23
|
+
This is narration only. Never include this name inside generated file content: not in ideas docs,
|
|
24
|
+
PRDs, or commit messages. The one existing exception is the Architecture Plan's Execution Log
|
|
25
|
+
(owned by `sf-architect`), which may reference it as a tracking label when this skill is dispatched
|
|
26
|
+
as a sub-agent task.
|
|
27
|
+
|
|
17
28
|
## Purpose
|
|
18
29
|
|
|
19
30
|
Generate actionable, prioritized enhancement ideas for one concrete, named thing — an existing
|
|
@@ -173,13 +184,13 @@ using the project's actual stack, referencing the anchor by name.
|
|
|
173
184
|
|
|
174
185
|
## Quick Triggers
|
|
175
186
|
|
|
176
|
-
| User says... | What to do
|
|
177
|
-
| ---------------------------------------------------------------- |
|
|
178
|
-
| "ide untuk [component]" | Anchor = that component. Read its code, run all 5 lenses, output enhancement table
|
|
179
|
-
| "ada ide baru?" (no name given) | No anchor — scan project, present real options via choice question, wait for selection
|
|
180
|
-
| "fitur baru apa yang bisa kita buat?" (no name given) | No anchor — ask whether to anchor on a closed PRD (list found ones) or describe a new area first
|
|
181
|
-
| "kira-kira [component] bisa ditambah apa?" | Anchor = that component. Focus on Functionality Gap + UX lenses first
|
|
182
|
-
| "apa next step dari PRD [name]?" | Anchor = that PRD (confirm it's closed/approved). Run Extension Questions
|
|
183
|
-
| "prioritas enhancement mana yang paling worth it?" | Requires a prior anchored ideation output in this conversation to rank — if none exists, ask which anchor to run first
|
|
184
|
-
| "ada yang bisa diimprove dari sisi performance?" (no name given) | No anchor — scan project, ask which component to focus the Performance lens on
|
|
187
|
+
| User says... | What to do |
|
|
188
|
+
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
189
|
+
| "ide untuk [component]" | Anchor = that component. Read its code, run all 5 lenses, output enhancement table |
|
|
190
|
+
| "ada ide baru?" (no name given) | No anchor — scan project, present real options via choice question, wait for selection |
|
|
191
|
+
| "fitur baru apa yang bisa kita buat?" (no name given) | No anchor — ask whether to anchor on a closed PRD (list found ones) or describe a new area first |
|
|
192
|
+
| "kira-kira [component] bisa ditambah apa?" | Anchor = that component. Focus on Functionality Gap + UX lenses first |
|
|
193
|
+
| "apa next step dari PRD [name]?" | Anchor = that PRD (confirm it's closed/approved). Run Extension Questions |
|
|
194
|
+
| "prioritas enhancement mana yang paling worth it?" | Requires a prior anchored ideation output in this conversation to rank — if none exists, ask which anchor to run first |
|
|
195
|
+
| "ada yang bisa diimprove dari sisi performance?" (no name given) | No anchor — scan project, ask which component to focus the Performance lens on |
|
|
185
196
|
| "let's build idea #[N]" / "jalankan ide nomor [N]" | Hand off — don't execute here. Route to `sf-architect` if it needs a technical decision, or `sf-ba` if it needs a PRD first |
|
|
@@ -12,6 +12,17 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
# Salesforce Security Review Skill
|
|
14
14
|
|
|
15
|
+
## Persona
|
|
16
|
+
|
|
17
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
18
|
+
|
|
19
|
+
`— Madison Ivy, sf-security-review`
|
|
20
|
+
|
|
21
|
+
This is narration only. Never include this name inside generated file content: not in CRs, audit
|
|
22
|
+
reports, code comments, or commit messages. The one existing exception is the Architecture Plan's
|
|
23
|
+
Execution Log (owned by `sf-architect`), which may reference it as a tracking label when this
|
|
24
|
+
skill is dispatched as a sub-agent task.
|
|
25
|
+
|
|
15
26
|
## Environment Context
|
|
16
27
|
|
|
17
28
|
- API Version: **not hardcoded** — new files inherit whatever `sourceApiVersion` is set in the
|
|
@@ -13,6 +13,17 @@ description: >
|
|
|
13
13
|
|
|
14
14
|
# Salesforce Testing Skill
|
|
15
15
|
|
|
16
|
+
## Persona
|
|
17
|
+
|
|
18
|
+
When this skill runs — standalone or dispatched as a sub-agent — open the response with:
|
|
19
|
+
|
|
20
|
+
`— Riley Reid, sf-testing`
|
|
21
|
+
|
|
22
|
+
This is narration only. Never include this name inside generated file content: not in PRDs, CRs,
|
|
23
|
+
Apex/LWC test code, code comments, or commit messages. The one existing exception is the
|
|
24
|
+
Architecture Plan's Execution Log (owned by `sf-architect`), which may reference it as a tracking
|
|
25
|
+
label when this skill is dispatched as a sub-agent task.
|
|
26
|
+
|
|
16
27
|
## Environment Context
|
|
17
28
|
|
|
18
29
|
- Minimum coverage: **85%** (aim for 90%+)
|
|
@@ -381,7 +392,7 @@ sf apex run test \
|
|
|
381
392
|
Every new or modified LWC component needs a Jest test file — same discipline as Apex coverage,
|
|
382
393
|
just not gated by a governor limit. This is separate from `sf-devops`'s LWC review checklist
|
|
383
394
|
(structural: naming, wire usage, JSDoc) and from `shaiden`'s design critique (visual/SLDS
|
|
384
|
-
compliance) — this section owns whether the component's
|
|
395
|
+
compliance) — this section owns whether the component's _behavior_ is actually tested.
|
|
385
396
|
|
|
386
397
|
### File Location
|
|
387
398
|
|
|
@@ -407,53 +418,55 @@ import getRelatedItems from '@salesforce/apex/MyController.getRelatedItems';
|
|
|
407
418
|
|
|
408
419
|
// Mock the wired Apex method — never let a Jest test hit a real Apex method
|
|
409
420
|
jest.mock(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
421
|
+
'@salesforce/apex/MyController.getRelatedItems',
|
|
422
|
+
() => ({ default: jest.fn() }),
|
|
423
|
+
{ virtual: true },
|
|
413
424
|
);
|
|
414
425
|
|
|
415
426
|
describe('c-my-component', () => {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
427
|
+
afterEach(() => {
|
|
428
|
+
while (document.body.firstChild) {
|
|
429
|
+
document.body.removeChild(document.body.firstChild);
|
|
430
|
+
}
|
|
431
|
+
jest.clearAllMocks();
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// ─── Happy Path ────────────────────────────────────────────────────────
|
|
435
|
+
it('renders items after the wire resolves', async () => {
|
|
436
|
+
const element = createElement('c-my-component', { is: MyComponent });
|
|
437
|
+
document.body.appendChild(element);
|
|
438
|
+
|
|
439
|
+
getRelatedItems.emit([{ Id: '001', Name: 'Test Item' }]);
|
|
440
|
+
await Promise.resolve();
|
|
441
|
+
|
|
442
|
+
const items = element.shadowRoot.querySelectorAll('.my-component__item');
|
|
443
|
+
expect(items.length).toBe(1);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// ─── Empty State ───────────────────────────────────────────────────────
|
|
447
|
+
it('shows the empty state when there is no data', async () => {
|
|
448
|
+
const element = createElement('c-my-component', { is: MyComponent });
|
|
449
|
+
document.body.appendChild(element);
|
|
450
|
+
|
|
451
|
+
getRelatedItems.emit([]);
|
|
452
|
+
await Promise.resolve();
|
|
453
|
+
|
|
454
|
+
expect(
|
|
455
|
+
element.shadowRoot.querySelector('.my-component__empty'),
|
|
456
|
+
).not.toBeNull();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// ─── Interaction / Error Path ──────────────────────────────────────────
|
|
460
|
+
it('fires the itemselected event on click', () => {
|
|
461
|
+
const element = createElement('c-my-component', { is: MyComponent });
|
|
462
|
+
document.body.appendChild(element);
|
|
463
|
+
|
|
464
|
+
const handler = jest.fn();
|
|
465
|
+
element.addEventListener('itemselected', handler);
|
|
466
|
+
element.shadowRoot.querySelector('button')?.click();
|
|
467
|
+
|
|
468
|
+
expect(handler).toHaveBeenCalled();
|
|
469
|
+
});
|
|
457
470
|
});
|
|
458
471
|
```
|
|
459
472
|
|