@codedrifters/configulator 0.0.205 → 0.0.207
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/lib/index.d.mts +29 -1
- package/lib/index.d.ts +29 -1
- package/lib/index.js +2441 -1269
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2439 -1269
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -228,6 +228,7 @@ __export(index_exports, {
|
|
|
228
228
|
jestBundle: () => jestBundle,
|
|
229
229
|
meetingAnalysisBundle: () => meetingAnalysisBundle,
|
|
230
230
|
orchestratorBundle: () => orchestratorBundle,
|
|
231
|
+
peopleProfileBundle: () => peopleProfileBundle,
|
|
231
232
|
pnpmBundle: () => pnpmBundle,
|
|
232
233
|
prReviewBundle: () => prReviewBundle,
|
|
233
234
|
projenBundle: () => projenBundle,
|
|
@@ -236,6 +237,7 @@ __export(index_exports, {
|
|
|
236
237
|
resolveModelAlias: () => resolveModelAlias,
|
|
237
238
|
resolveTemplateVariables: () => resolveTemplateVariables,
|
|
238
239
|
slackBundle: () => slackBundle,
|
|
240
|
+
softwareProfileBundle: () => softwareProfileBundle,
|
|
239
241
|
turborepoBundle: () => turborepoBundle,
|
|
240
242
|
typescriptBundle: () => typescriptBundle,
|
|
241
243
|
vitestBundle: () => vitestBundle
|
|
@@ -2715,506 +2717,522 @@ var orchestratorBundle = {
|
|
|
2715
2717
|
}
|
|
2716
2718
|
};
|
|
2717
2719
|
|
|
2718
|
-
// src/
|
|
2719
|
-
var
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
ZERO_DAYS: 0,
|
|
2723
|
-
ONE_HOUR: 60,
|
|
2724
|
-
SIX_HOURS: 360,
|
|
2725
|
-
TWELVE_HOURS: 720,
|
|
2726
|
-
ONE_DAY: 1440,
|
|
2727
|
-
TWO_DAYS: 2880,
|
|
2728
|
-
THREE_DAYS: 4320,
|
|
2729
|
-
FOUR_DAYS: 5760,
|
|
2730
|
-
FIVE_DAYS: 7200,
|
|
2731
|
-
SIX_DAYS: 8640,
|
|
2732
|
-
ONE_WEEK: 10080
|
|
2733
|
-
};
|
|
2734
|
-
var PnpmWorkspace = class _PnpmWorkspace extends import_projen.Component {
|
|
2735
|
-
/**
|
|
2736
|
-
* Get the pnpm workspace component of a project. If it does not exist,
|
|
2737
|
-
* return undefined.
|
|
2738
|
-
*
|
|
2739
|
-
* @param project
|
|
2740
|
-
* @returns
|
|
2741
|
-
*/
|
|
2742
|
-
static of(project) {
|
|
2743
|
-
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
2744
|
-
return project.root.components.find(isDefined);
|
|
2745
|
-
}
|
|
2746
|
-
constructor(project, options = {}) {
|
|
2747
|
-
super(project);
|
|
2748
|
-
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
2749
|
-
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
2750
|
-
this.minimumReleaseAge = options.minimumReleaseAge ?? MINIMUM_RELEASE_AGE.ONE_DAY;
|
|
2751
|
-
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
2752
|
-
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
2753
|
-
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
2754
|
-
this.subprojects = options.subprojects ?? [];
|
|
2755
|
-
this.defaultCatalog = options.defaultCatalog;
|
|
2756
|
-
this.namedCatalogs = options.namedCatalogs;
|
|
2757
|
-
project.addPackageIgnore(this.fileName);
|
|
2758
|
-
new import_projen.YamlFile(this.project, this.fileName, {
|
|
2759
|
-
obj: () => {
|
|
2760
|
-
const pnpmConfig = {};
|
|
2761
|
-
const packages = new Array();
|
|
2762
|
-
for (const subproject of project.subprojects) {
|
|
2763
|
-
packages.push((0, import_path.relative)(this.project.outdir, subproject.outdir));
|
|
2764
|
-
}
|
|
2765
|
-
const packageSet = new Set(packages);
|
|
2766
|
-
for (const subprojectPath of this.subprojects) {
|
|
2767
|
-
packageSet.add(subprojectPath);
|
|
2768
|
-
}
|
|
2769
|
-
if (this.subprojects.length > 0) {
|
|
2770
|
-
packages.length = 0;
|
|
2771
|
-
packages.push(...packageSet);
|
|
2772
|
-
}
|
|
2773
|
-
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
2774
|
-
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
2775
|
-
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
2776
|
-
}
|
|
2777
|
-
if (this.onlyBuiltDependencies.length > 0) {
|
|
2778
|
-
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
2779
|
-
}
|
|
2780
|
-
if (this.ignoredBuiltDependencies.length > 0) {
|
|
2781
|
-
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
2782
|
-
}
|
|
2783
|
-
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
2784
|
-
pnpmConfig.catalog = this.defaultCatalog;
|
|
2785
|
-
}
|
|
2786
|
-
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
2787
|
-
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
2788
|
-
}
|
|
2789
|
-
return {
|
|
2790
|
-
...packages.length > 0 ? { packages } : {},
|
|
2791
|
-
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
2792
|
-
};
|
|
2793
|
-
}
|
|
2794
|
-
});
|
|
2795
|
-
}
|
|
2796
|
-
};
|
|
2797
|
-
var MIMIMUM_RELEASE_AGE = MINIMUM_RELEASE_AGE;
|
|
2798
|
-
|
|
2799
|
-
// src/agent/bundles/pnpm.ts
|
|
2800
|
-
var pnpmBundle = {
|
|
2801
|
-
name: "pnpm",
|
|
2802
|
-
description: "PNPM workspace rules and dependency management conventions",
|
|
2803
|
-
appliesWhen: (project) => hasComponent(project, PnpmWorkspace),
|
|
2804
|
-
rules: [
|
|
2805
|
-
{
|
|
2806
|
-
name: "pnpm-workspace",
|
|
2807
|
-
description: "PNPM workspace and dependency management conventions",
|
|
2808
|
-
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
2809
|
-
filePatterns: ["package.json", "pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
2810
|
-
content: [
|
|
2811
|
-
"# PNPM Workspace Conventions",
|
|
2812
|
-
"",
|
|
2813
|
-
"## Package Management",
|
|
2814
|
-
"",
|
|
2815
|
-
"- Use **PNPM** for package management",
|
|
2816
|
-
"- Workspace configuration in `pnpm-workspace.yaml`",
|
|
2817
|
-
"- Dependencies managed through Projen, not directly in `package.json`",
|
|
2818
|
-
"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo",
|
|
2819
|
-
"- Never use published NPM versions of internal packages; always reference the local workspace version",
|
|
2820
|
-
"",
|
|
2821
|
-
"## Dependency Management",
|
|
2822
|
-
"",
|
|
2823
|
-
"**DO:**",
|
|
2824
|
-
"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)",
|
|
2825
|
-
"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration",
|
|
2826
|
-
'- Use catalog dependencies when available (e.g., `"aws-cdk-lib@catalog:"`)',
|
|
2827
|
-
"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration",
|
|
2828
|
-
"",
|
|
2829
|
-
"**DO NOT:**",
|
|
2830
|
-
"- Run `npm install some-package`",
|
|
2831
|
-
"- Run `pnpm add some-package`",
|
|
2832
|
-
"- Run `yarn add some-package`",
|
|
2833
|
-
"- Manually edit `package.json` dependencies",
|
|
2834
|
-
"",
|
|
2835
|
-
"Manual package installation creates conflicts with Projen-managed files."
|
|
2836
|
-
].join("\n"),
|
|
2837
|
-
tags: ["workflow"]
|
|
2838
|
-
}
|
|
2839
|
-
]
|
|
2840
|
-
};
|
|
2841
|
-
|
|
2842
|
-
// src/agent/bundles/pr-review.ts
|
|
2843
|
-
var prReviewerSubAgent = {
|
|
2844
|
-
name: "pr-reviewer",
|
|
2845
|
-
description: "Reviews a pull request against its linked issue's acceptance criteria, then enables squash auto-merge or comments with findings",
|
|
2720
|
+
// src/agent/bundles/people-profile.ts
|
|
2721
|
+
var peopleProfileAnalystSubAgent = {
|
|
2722
|
+
name: "people-profile-analyst",
|
|
2723
|
+
description: "Researches an individual person (colleague, customer contact, vendor contact, partner contact, industry expert, or connector) from public sources and produces a structured markdown profile cross-linked to companies, software, and meeting notes. One person per session, tracked by people:* GitHub issue labels.",
|
|
2846
2724
|
model: AGENT_MODEL.POWERFUL,
|
|
2847
|
-
maxTurns:
|
|
2725
|
+
maxTurns: 80,
|
|
2848
2726
|
platforms: { cursor: { exclude: true } },
|
|
2849
2727
|
prompt: [
|
|
2850
|
-
"#
|
|
2728
|
+
"# People Profile Analyst Agent",
|
|
2851
2729
|
"",
|
|
2852
|
-
"You
|
|
2853
|
-
"
|
|
2854
|
-
"
|
|
2855
|
-
"
|
|
2856
|
-
"
|
|
2857
|
-
"
|
|
2730
|
+
"You research a single person from public sources and write a",
|
|
2731
|
+
"structured markdown profile. Each profile cycle runs across a small",
|
|
2732
|
+
"sequence of GitHub issues \u2014 one per phase \u2014 and produces a single",
|
|
2733
|
+
"profile file on disk plus cross-references to related entities",
|
|
2734
|
+
"(companies, software, meeting notes) already tracked elsewhere in",
|
|
2735
|
+
"the project.",
|
|
2736
|
+
"",
|
|
2737
|
+
"This agent is **domain-neutral**. It makes no assumptions about what",
|
|
2738
|
+
"the consuming project sells, which industry it serves, or which",
|
|
2739
|
+
"people matter to it. All domain-specific vocabulary, output",
|
|
2740
|
+
"locations, cross-reference targets, and profile-template overrides",
|
|
2741
|
+
"come from the invoking issue body or the consuming project's",
|
|
2742
|
+
"configuration.",
|
|
2743
|
+
"",
|
|
2744
|
+
"Follow your project's shared agent conventions (`AGENTS.md`,",
|
|
2745
|
+
"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.",
|
|
2858
2746
|
"",
|
|
2859
2747
|
"---",
|
|
2860
2748
|
"",
|
|
2861
2749
|
...PROJECT_CONTEXT_READER_SECTION,
|
|
2862
|
-
"##
|
|
2750
|
+
"## Design Principles",
|
|
2863
2751
|
"",
|
|
2864
|
-
"
|
|
2865
|
-
"
|
|
2752
|
+
"1. **One person per session.** Never profile two people in a single",
|
|
2753
|
+
" session, even if they came up together (e.g. co-founders).",
|
|
2754
|
+
"2. **Public sources only.** Use the person's own public writing,",
|
|
2755
|
+
" company bios, conference talks, public interviews, and similar",
|
|
2756
|
+
" public material. Do not attempt to access gated or paywalled",
|
|
2757
|
+
" content unless the invoking issue body explicitly authorizes it.",
|
|
2758
|
+
"3. **Filesystem durability.** The profile file is the deliverable. It",
|
|
2759
|
+
" is committed to disk before the profile issue closes. Downstream",
|
|
2760
|
+
" phases read from disk \u2014 never rely on session memory.",
|
|
2761
|
+
"4. **Generic over specific.** No hardcoded role types, taxonomies, or",
|
|
2762
|
+
" relationship assumptions. Use the generic person-role taxonomy",
|
|
2763
|
+
" below and let consuming projects override it.",
|
|
2764
|
+
"5. **Cite everything.** Every non-trivial factual claim in the",
|
|
2765
|
+
" profile must carry a source citation (URL plus access date).",
|
|
2766
|
+
"6. **Respect privacy.** Profile only public, professional information.",
|
|
2767
|
+
" Never capture home addresses, personal phone numbers, family",
|
|
2768
|
+
" details, health information, or other private data even when",
|
|
2769
|
+
" encountered in public sources.",
|
|
2770
|
+
"7. **Cross-reference, don't duplicate.** When the profile mentions a",
|
|
2771
|
+
" company, software product, or meeting already tracked by the",
|
|
2772
|
+
" consuming project, link to the existing artifact rather than",
|
|
2773
|
+
" duplicating its content. Do not create downstream research",
|
|
2774
|
+
" issues for these cross-references \u2014 only link.",
|
|
2866
2775
|
"",
|
|
2867
|
-
"
|
|
2776
|
+
"---",
|
|
2868
2777
|
"",
|
|
2869
|
-
"
|
|
2778
|
+
"## Person Role Taxonomy",
|
|
2870
2779
|
"",
|
|
2871
|
-
"
|
|
2872
|
-
"
|
|
2873
|
-
"
|
|
2780
|
+
"Pick exactly one role per person profile. The taxonomy is",
|
|
2781
|
+
"deliberately generic \u2014 consuming projects override it via",
|
|
2782
|
+
"`agentConfig.rules` if they need a domain-specific refinement.",
|
|
2874
2783
|
"",
|
|
2875
|
-
"
|
|
2784
|
+
"| Role | Use for |",
|
|
2785
|
+
"|------|---------|",
|
|
2786
|
+
"| `colleague` | People inside your own organization worth tracking (teammates, cross-functional partners, leadership). |",
|
|
2787
|
+
"| `customer-contact` | Named individuals at existing or prospective customer accounts. |",
|
|
2788
|
+
"| `vendor-contact` | Named individuals at vendors, suppliers, or software providers you depend on. |",
|
|
2789
|
+
"| `partner-contact` | Named individuals at strategic, channel, or integration partners. |",
|
|
2790
|
+
"| `industry-expert` | Analysts, researchers, journalists, or well-known practitioners whose work shapes the market. |",
|
|
2791
|
+
"| `connector` | People who primarily provide introductions, referrals, or access across networks \u2014 advisors, investors acting as connectors, community hubs. |",
|
|
2876
2792
|
"",
|
|
2877
|
-
|
|
2878
|
-
"
|
|
2879
|
-
"
|
|
2880
|
-
" `ERROR` conclusion on a required check disqualifies the PR.",
|
|
2881
|
-
"3. The PR body contains a linked issue via one of the closing keywords:",
|
|
2882
|
-
" `Closes #N`, `Fixes #N`, or `Resolves #N` (case-insensitive).",
|
|
2793
|
+
"If the person plausibly fits two roles, prefer the one that reflects",
|
|
2794
|
+
"the **reason the profile was requested**, and note the secondary",
|
|
2795
|
+
"role in the profile body.",
|
|
2883
2796
|
"",
|
|
2884
|
-
"
|
|
2885
|
-
"stop. Do not proceed to full review.",
|
|
2797
|
+
"---",
|
|
2886
2798
|
"",
|
|
2887
|
-
"
|
|
2888
|
-
"
|
|
2799
|
+
"## State Machine Overview",
|
|
2800
|
+
"",
|
|
2801
|
+
"```",
|
|
2802
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
2803
|
+
"\u2502 1. RESEARCH \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 2. DRAFT PROFILE \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 3. FOLLOWUP \u2502",
|
|
2804
|
+
"\u2502 Collect public \u2502 \u2502 Write the structured \u2502 \u2502 Cross-link the \u2502",
|
|
2805
|
+
"\u2502 sources into a \u2502 \u2502 markdown profile to \u2502 \u2502 profile to existing\u2502",
|
|
2806
|
+
"\u2502 bounded notes \u2502 \u2502 the configured path \u2502 \u2502 companies, software\u2502",
|
|
2807
|
+
"\u2502 file \u2502 \u2502 \u2502 \u2502 and meeting notes \u2502",
|
|
2808
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
2889
2809
|
"```",
|
|
2890
2810
|
"",
|
|
2891
|
-
"
|
|
2811
|
+
"**Issue labels encode the phase:**",
|
|
2892
2812
|
"",
|
|
2893
|
-
"
|
|
2894
|
-
"
|
|
2895
|
-
"
|
|
2813
|
+
"| Label | Phase | Session work |",
|
|
2814
|
+
"|-------|-------|-------------|",
|
|
2815
|
+
"| `people:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |",
|
|
2816
|
+
"| `people:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup issue if warranted. |",
|
|
2817
|
+
"| `people:followup` | 3. Followup | Read the profile. Update cross-references to existing companies, software, and meeting notes. No new downstream issues. |",
|
|
2896
2818
|
"",
|
|
2897
|
-
"
|
|
2819
|
+
"All issues also carry `type:people-profile` and a `status:*` label.",
|
|
2898
2820
|
"",
|
|
2899
|
-
"
|
|
2900
|
-
"
|
|
2901
|
-
"
|
|
2902
|
-
"gh pr checks <pr-number>",
|
|
2903
|
-
"```",
|
|
2821
|
+
"**Issue count per person cycle:** 1 research + 1 draft + 0\u20131 followup =",
|
|
2822
|
+
"**2\u20133 sessions**. The followup phase is skipped when the profile did",
|
|
2823
|
+
"not surface any cross-references worth linking.",
|
|
2904
2824
|
"",
|
|
2905
|
-
"
|
|
2906
|
-
"
|
|
2825
|
+
"**Shortened paths:**",
|
|
2826
|
+
"- Research phase determines the person is out of scope (not",
|
|
2827
|
+
" relevant, insufficient public material) \u2192 research issue closes",
|
|
2828
|
+
" with a justification and no downstream issues are created \u2192 **1 session**.",
|
|
2829
|
+
"- Short profile with no cross-references needed \u2192 **2 sessions**.",
|
|
2907
2830
|
"",
|
|
2908
|
-
"
|
|
2831
|
+
"---",
|
|
2909
2832
|
"",
|
|
2910
|
-
"
|
|
2911
|
-
"gh issue view <issue-number>",
|
|
2912
|
-
"```",
|
|
2833
|
+
"## Configurable Paths",
|
|
2913
2834
|
"",
|
|
2914
|
-
"
|
|
2835
|
+
"The pipeline uses these placeholders. Consuming projects override the",
|
|
2836
|
+
"defaults by passing paths in the `/profile-person` skill invocation",
|
|
2837
|
+
"or by extending this rule in their own `agentConfig.rules`.",
|
|
2915
2838
|
"",
|
|
2916
|
-
"
|
|
2917
|
-
"
|
|
2839
|
+
"| Placeholder | Meaning | Default |",
|
|
2840
|
+
"|-------------|---------|---------|",
|
|
2841
|
+
"| `<PEOPLE_ROOT>` | Root folder for person profiles | `docs/people/` |",
|
|
2842
|
+
"| `<PROFILES_DIR>` | Final person profile files | `<PEOPLE_ROOT>/profiles/` |",
|
|
2843
|
+
"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<PEOPLE_ROOT>/notes/` |",
|
|
2844
|
+
"| `<PERSON_SLUG>` | Short kebab-case slug identifying the person | derived from the person's name |",
|
|
2845
|
+
"| `<COMPANIES_DIR>` | Where existing company profiles live (for cross-references) | `docs/companies/profiles/` |",
|
|
2846
|
+
"| `<SOFTWARE_DIR>` | Where existing software profiles live (for cross-references) | `docs/software/profiles/` |",
|
|
2847
|
+
"| `<MEETINGS_DIR>` | Where meeting notes live (for cross-references) | `docs/meetings/` |",
|
|
2848
|
+
"",
|
|
2849
|
+
"If `docs/project-context.md` specifies a different people-research",
|
|
2850
|
+
"tree or cross-reference target, prefer that. Otherwise fall back to",
|
|
2851
|
+
"the defaults above. Cross-reference directories are read-only \u2014 this",
|
|
2852
|
+
"agent never writes into them.",
|
|
2918
2853
|
"",
|
|
2919
|
-
"
|
|
2920
|
-
"2. Mark it as `met`, `partial`, or `missing`.",
|
|
2921
|
-
"3. Record the specific files / functions / tests that provide evidence.",
|
|
2854
|
+
"---",
|
|
2922
2855
|
"",
|
|
2923
|
-
"
|
|
2856
|
+
"## Refresh Cadence",
|
|
2924
2857
|
"",
|
|
2925
|
-
"
|
|
2926
|
-
"
|
|
2927
|
-
"- **Test coverage** \u2014 new or changed behavior has tests",
|
|
2928
|
-
"- **CI status** \u2014 `gh pr checks` reports all required checks passing",
|
|
2929
|
-
"- **Scope creep** \u2014 diff stays within the issue's stated scope",
|
|
2858
|
+
"Profiles go stale. A person changes jobs, publishes new work, or",
|
|
2859
|
+
"shifts focus. The pipeline supports a configurable refresh cadence:",
|
|
2930
2860
|
"",
|
|
2931
|
-
"
|
|
2861
|
+
"- **Default cadence:** 180 days from the profile's `date` frontmatter.",
|
|
2862
|
+
"- **Override:** the invoking issue body may specify a `refresh_days: N`",
|
|
2863
|
+
" field, or the consuming project may set a project-wide default in",
|
|
2864
|
+
" `docs/project-context.md`.",
|
|
2932
2865
|
"",
|
|
2933
|
-
"
|
|
2866
|
+
"When the `/profile-person` skill is invoked for a slug that already",
|
|
2867
|
+
"has a profile:",
|
|
2934
2868
|
"",
|
|
2935
|
-
"
|
|
2936
|
-
"
|
|
2869
|
+
"- If the profile is **younger** than the refresh cadence, the skill",
|
|
2870
|
+
" exits with a message pointing to the existing profile. Pass",
|
|
2871
|
+
" `force: true` in the issue body to refresh anyway.",
|
|
2872
|
+
"- If the profile is **older** than the refresh cadence, the pipeline",
|
|
2873
|
+
" proceeds in update-in-place mode: Phase 2 edits the existing file,",
|
|
2874
|
+
" preserves its slug, and bumps the `date` frontmatter.",
|
|
2937
2875
|
"",
|
|
2938
|
-
"
|
|
2939
|
-
"
|
|
2940
|
-
"
|
|
2941
|
-
" --body '<extended-description>'",
|
|
2942
|
-
"```",
|
|
2876
|
+
"Refresh mode never changes the profile's role without an explicit",
|
|
2877
|
+
"override in the refresh request \u2014 role changes are material and",
|
|
2878
|
+
"warrant a human review step.",
|
|
2943
2879
|
"",
|
|
2944
|
-
"
|
|
2945
|
-
"`feat(scope): description`). The body should bullet the changes and end",
|
|
2946
|
-
"with `Closes #<issue-number>`.",
|
|
2880
|
+
"---",
|
|
2947
2881
|
"",
|
|
2948
|
-
"
|
|
2882
|
+
"## Agent Loop",
|
|
2949
2883
|
"",
|
|
2950
|
-
"
|
|
2884
|
+
"Run this loop exactly once per session. Never start a second issue.",
|
|
2951
2885
|
"",
|
|
2952
|
-
"
|
|
2953
|
-
"
|
|
2954
|
-
"
|
|
2886
|
+
"1. Claim one open `type:people-profile` issue using phase priority:",
|
|
2887
|
+
" `people:research` > `people:draft` > `people:followup`.",
|
|
2888
|
+
"2. Transition `status:ready` \u2192 `status:in-progress` and create the",
|
|
2889
|
+
" branch per your project's branch-naming convention.",
|
|
2890
|
+
"3. Execute the phase handler that matches the issue's `people:*`",
|
|
2891
|
+
" label.",
|
|
2892
|
+
"4. Commit, push, open a PR (if applicable), and close the issue per",
|
|
2893
|
+
" your project's PR workflow.",
|
|
2955
2894
|
"",
|
|
2956
|
-
"
|
|
2957
|
-
"For each blocking finding, cite the unmet acceptance criterion and the",
|
|
2958
|
-
"file or function the gap lives in. Do **not** merge, and do **not** push",
|
|
2959
|
-
"any commits to the PR's branch.",
|
|
2895
|
+
"---",
|
|
2960
2896
|
"",
|
|
2961
|
-
"
|
|
2962
|
-
"--request-changes`: it is lighter-weight, doesn't require the author to",
|
|
2963
|
-
"dismiss a formal review, and composes cleanly with the multi-PR loop.",
|
|
2897
|
+
"## Phase 1: Research (`people:research`)",
|
|
2964
2898
|
"",
|
|
2965
|
-
"
|
|
2899
|
+
"**Goal:** Gather public sources into a bounded research-notes file.",
|
|
2966
2900
|
"",
|
|
2967
|
-
"
|
|
2968
|
-
"
|
|
2901
|
+
"**Budget:** Public web search only, unless the issue body authorizes",
|
|
2902
|
+
"additional sources. Write one notes file. Do not write the profile",
|
|
2903
|
+
"in this phase.",
|
|
2969
2904
|
"",
|
|
2970
|
-
"
|
|
2971
|
-
"gh pr view <pr-number> --json state --jq '.state'",
|
|
2972
|
-
"```",
|
|
2905
|
+
"### Steps",
|
|
2973
2906
|
"",
|
|
2974
|
-
"
|
|
2975
|
-
"
|
|
2976
|
-
"
|
|
2977
|
-
"
|
|
2978
|
-
"
|
|
2979
|
-
"
|
|
2980
|
-
"
|
|
2981
|
-
"
|
|
2982
|
-
"
|
|
2983
|
-
"
|
|
2984
|
-
"
|
|
2985
|
-
"
|
|
2986
|
-
"
|
|
2987
|
-
"
|
|
2988
|
-
"
|
|
2989
|
-
"
|
|
2990
|
-
"
|
|
2991
|
-
"
|
|
2992
|
-
"-
|
|
2907
|
+
"1. **Read the issue body.** It should include:",
|
|
2908
|
+
" - The person's name and primary affiliation (company) if known",
|
|
2909
|
+
" - The requested role from the taxonomy above",
|
|
2910
|
+
" - The reason the profile was requested (framing \u2014 what does the",
|
|
2911
|
+
" invoking project want to learn?)",
|
|
2912
|
+
" - Optional: `<PERSON_SLUG>` override, custom output paths,",
|
|
2913
|
+
" `refresh_days` override, `force: true` for out-of-cadence refresh",
|
|
2914
|
+
"",
|
|
2915
|
+
"2. **Derive `<PERSON_SLUG>`** if not supplied \u2014 a 2\u20134 word kebab-case",
|
|
2916
|
+
" summary of the person's name. Disambiguate against any existing",
|
|
2917
|
+
" slug under `<PROFILES_DIR>/` or `<NOTES_DIR>/` by appending a",
|
|
2918
|
+
" company or role qualifier (e.g. `jane-doe-acme`).",
|
|
2919
|
+
"",
|
|
2920
|
+
"3. **Check for an existing profile.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`",
|
|
2921
|
+
" exists, read its `date` frontmatter and apply the refresh cadence",
|
|
2922
|
+
" rules above before proceeding.",
|
|
2923
|
+
"",
|
|
2924
|
+
"4. **Gather sources.** Prioritize in this order:",
|
|
2925
|
+
" - The person's own public writing (personal site, blog, newsletter)",
|
|
2926
|
+
" - Their current employer's bio / leadership page",
|
|
2927
|
+
" - Public conference talks, podcast appearances, and interviews",
|
|
2928
|
+
" - Public directories that the invoking issue body authorizes",
|
|
2929
|
+
" (LinkedIn, GitHub, company profiles, Crunchbase)",
|
|
2930
|
+
" - Public contributions (open-source repos, published papers)",
|
|
2931
|
+
"",
|
|
2932
|
+
"5. **Write a research-notes file** to",
|
|
2933
|
+
" `<NOTES_DIR>/<PERSON_SLUG>.notes.md`:",
|
|
2934
|
+
"",
|
|
2935
|
+
" ```markdown",
|
|
2936
|
+
" ---",
|
|
2937
|
+
' title: "Research Notes: <person name>"',
|
|
2938
|
+
" slug: <PERSON_SLUG>",
|
|
2939
|
+
" role: <one of the taxonomy values>",
|
|
2940
|
+
" primary_company: <company name if known>",
|
|
2941
|
+
" date: YYYY-MM-DD",
|
|
2942
|
+
" parent_issue: <N>",
|
|
2943
|
+
" ---",
|
|
2944
|
+
"",
|
|
2945
|
+
" # Research Notes: <person name>",
|
|
2946
|
+
"",
|
|
2947
|
+
" ## Framing",
|
|
2948
|
+
" <why this person was requested and what to learn>",
|
|
2949
|
+
"",
|
|
2950
|
+
" ## Raw Findings",
|
|
2951
|
+
" - <finding> \u2014 source: <citation>",
|
|
2952
|
+
"",
|
|
2953
|
+
" ## Candidate Cross-References",
|
|
2954
|
+
" - **Companies mentioned:** <list of company names>",
|
|
2955
|
+
" - **Software mentioned:** <list of product names>",
|
|
2956
|
+
" - **Meetings mentioned:** <list of meeting identifiers>",
|
|
2957
|
+
"",
|
|
2958
|
+
" ## Open Questions",
|
|
2959
|
+
" <anything the notes could not answer from public sources>",
|
|
2960
|
+
"",
|
|
2961
|
+
" ## Sources",
|
|
2962
|
+
" - <source URL or file path> \u2014 <date accessed>",
|
|
2963
|
+
" ```",
|
|
2964
|
+
"",
|
|
2965
|
+
"6. **Create the `people:draft` issue** with `Depends on: #<research-issue>`.",
|
|
2966
|
+
" Its body references the notes file path, the requested role, and",
|
|
2967
|
+
" any refresh-mode flags.",
|
|
2968
|
+
"",
|
|
2969
|
+
"7. **Commit and push** the notes file. Close the research issue.",
|
|
2993
2970
|
"",
|
|
2994
2971
|
"---",
|
|
2995
2972
|
"",
|
|
2996
|
-
"##
|
|
2973
|
+
"## Phase 2: Draft Profile (`people:draft`)",
|
|
2997
2974
|
"",
|
|
2998
|
-
"
|
|
2975
|
+
"**Goal:** Write the structured person profile from the research notes.",
|
|
2999
2976
|
"",
|
|
3000
|
-
"
|
|
3001
|
-
"
|
|
3002
|
-
"Linked issue: #<issue-number>",
|
|
3003
|
-
"Verdict: AUTO_MERGE_ENABLED | NEEDS_CHANGES | INELIGIBLE | BLOCKED",
|
|
2977
|
+
"**Budget:** No new web searches unless explicitly needed to fill a",
|
|
2978
|
+
"gap the notes flagged. Write one profile file.",
|
|
3004
2979
|
"",
|
|
3005
|
-
"
|
|
3006
|
-
" [x] <criterion> \u2014 <evidence>",
|
|
3007
|
-
" [~] <criterion> \u2014 partial: <gap>",
|
|
3008
|
-
" [ ] <criterion> \u2014 missing",
|
|
2980
|
+
"### Steps",
|
|
3009
2981
|
"",
|
|
3010
|
-
"
|
|
3011
|
-
" - Blocking: <items>",
|
|
3012
|
-
" - Suggested: <items>",
|
|
3013
|
-
" - Nitpick: <items>",
|
|
2982
|
+
"1. **Read the research-notes file** referenced in the issue body.",
|
|
3014
2983
|
"",
|
|
3015
|
-
"
|
|
3016
|
-
"
|
|
3017
|
-
"
|
|
3018
|
-
"
|
|
2984
|
+
"2. **Check for duplicates / refresh.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`",
|
|
2985
|
+
" already exists:",
|
|
2986
|
+
" - In refresh mode, open the existing file and update in place,",
|
|
2987
|
+
" preserving the slug and bumping the `date` frontmatter.",
|
|
2988
|
+
" - Otherwise, flag a naming collision and stop \u2014 never silently",
|
|
2989
|
+
" overwrite a non-trivial existing profile.",
|
|
2990
|
+
"",
|
|
2991
|
+
"3. **Write the profile** to `<PROFILES_DIR>/<PERSON_SLUG>.md` using",
|
|
2992
|
+
" the template below. All sections are required; use",
|
|
2993
|
+
" `_Not available in public sources._` when a section cannot be",
|
|
2994
|
+
" filled from the notes.",
|
|
2995
|
+
"",
|
|
2996
|
+
" ```markdown",
|
|
2997
|
+
" ---",
|
|
2998
|
+
' title: "<person name>"',
|
|
2999
|
+
" slug: <PERSON_SLUG>",
|
|
3000
|
+
" role: <one of the taxonomy values>",
|
|
3001
|
+
" primary_company: <company name>",
|
|
3002
|
+
" date: YYYY-MM-DD",
|
|
3003
|
+
" refresh_days: <N, default 180>",
|
|
3004
|
+
" parent_issue: <N>",
|
|
3005
|
+
" notes: <NOTES_DIR>/<PERSON_SLUG>.notes.md",
|
|
3006
|
+
" ---",
|
|
3007
|
+
"",
|
|
3008
|
+
" # <person name>",
|
|
3009
|
+
"",
|
|
3010
|
+
" ## Summary",
|
|
3011
|
+
" <2\u20134 sentence elevator description: who they are, what they do,",
|
|
3012
|
+
" why they matter to this project>",
|
|
3013
|
+
"",
|
|
3014
|
+
" ## Classification",
|
|
3015
|
+
" - **Primary role:** <taxonomy value>",
|
|
3016
|
+
" - **Secondary role (if any):** <taxonomy value or `n/a`>",
|
|
3017
|
+
" - **Relevance to this project:** <1\u20132 sentences tying the person",
|
|
3018
|
+
" back to the framing from the notes>",
|
|
3019
|
+
"",
|
|
3020
|
+
" ## Current Position",
|
|
3021
|
+
" - **Company:** <primary company \u2014 link to company profile if tracked>",
|
|
3022
|
+
" - **Title:** <current title>",
|
|
3023
|
+
" - **Tenure:** <since YYYY, if known>",
|
|
3024
|
+
" - **Focus areas:** <what they work on day-to-day>",
|
|
3025
|
+
"",
|
|
3026
|
+
" ## Background",
|
|
3027
|
+
" - **Prior roles:** <short reverse-chronological list>",
|
|
3028
|
+
" - **Education / credentials:** <if publicly disclosed>",
|
|
3029
|
+
" - **Notable contributions:** <open-source, publications, talks>",
|
|
3030
|
+
"",
|
|
3031
|
+
" ## Expertise Signals",
|
|
3032
|
+
" <topics they write or speak about \u2014 each bullet cited to a public",
|
|
3033
|
+
" source>",
|
|
3034
|
+
"",
|
|
3035
|
+
" ## Positioning / Point of View",
|
|
3036
|
+
" <how they describe their own work and views \u2014 use their own",
|
|
3037
|
+
" language, cited, rather than inferred>",
|
|
3038
|
+
"",
|
|
3039
|
+
" ## Cross-References",
|
|
3040
|
+
" - **Companies:** <links to `<COMPANIES_DIR>/*.md` for companies",
|
|
3041
|
+
" already tracked by this project>",
|
|
3042
|
+
" - **Software:** <links to `<SOFTWARE_DIR>/*.md` for software",
|
|
3043
|
+
" already tracked by this project>",
|
|
3044
|
+
" - **Meetings:** <links to `<MEETINGS_DIR>/*.md` for meeting notes",
|
|
3045
|
+
" this person participated in>",
|
|
3046
|
+
"",
|
|
3047
|
+
" ## Contact Preferences",
|
|
3048
|
+
" <public channels only \u2014 company email if listed, social handles,",
|
|
3049
|
+
" speaker inquiry forms. Never private contact info.>",
|
|
3050
|
+
"",
|
|
3051
|
+
" ## Risks / Open Questions",
|
|
3052
|
+
" <what the profile could not answer; flag anything the followup",
|
|
3053
|
+
" phase should cross-reference>",
|
|
3054
|
+
"",
|
|
3055
|
+
" ## Sources",
|
|
3056
|
+
" - <source URL> \u2014 <date accessed>",
|
|
3057
|
+
" ```",
|
|
3058
|
+
"",
|
|
3059
|
+
"4. **Decide whether a followup issue is warranted.** Create a",
|
|
3060
|
+
" `people:followup` issue (depending on this draft issue) only if",
|
|
3061
|
+
" the profile's Candidate Cross-References lists at least one",
|
|
3062
|
+
" company, software product, or meeting already tracked by the",
|
|
3063
|
+
" consuming project. Otherwise, note in the draft issue's closing",
|
|
3064
|
+
" comment that no followup is needed.",
|
|
3065
|
+
"",
|
|
3066
|
+
"5. **Commit and push** the profile file. Close the draft issue.",
|
|
3019
3067
|
"",
|
|
3020
3068
|
"---",
|
|
3021
3069
|
"",
|
|
3022
|
-
"##
|
|
3070
|
+
"## Phase 3: Followup (`people:followup`)",
|
|
3023
3071
|
"",
|
|
3024
|
-
"
|
|
3025
|
-
"
|
|
3026
|
-
"
|
|
3027
|
-
"2. **Never merge without a linked issue.** If the PR body has no",
|
|
3028
|
-
" `Closes #N` / `Fixes #N` / `Resolves #N`, comment and stop.",
|
|
3029
|
-
"3. **Never merge with failing CI.** Even if every criterion is met,",
|
|
3030
|
-
" block on red checks.",
|
|
3031
|
-
"4. **Never bypass review conventions.** Always use `--squash`, `--auto`,",
|
|
3032
|
-
" and `--delete-branch` for merges. Do not force-merge.",
|
|
3033
|
-
"5. **Do not implement code.** You review, decide, and orchestrate. If",
|
|
3034
|
-
" the PR needs changes, comment and stop.",
|
|
3035
|
-
"6. **Never push commits to the PR's branch.** If the PR needs changes,",
|
|
3036
|
-
" comment and stop \u2014 do not attempt to fix it yourself. The PR author",
|
|
3037
|
-
" owns the branch; pushing to someone else's branch is out of scope.",
|
|
3038
|
-
"7. **In loop mode (`/review-prs`), never stop early.** If any review",
|
|
3039
|
-
" fails, comment and move to the next PR. Only abort the loop on a",
|
|
3040
|
-
" fatal error (e.g. `gh` auth failure, network outage).",
|
|
3041
|
-
"8. **Follow CLAUDE.md conventions** for all `git` and `gh` operations."
|
|
3042
|
-
].join("\n")
|
|
3043
|
-
};
|
|
3044
|
-
var reviewPrSkill = {
|
|
3045
|
-
name: "review-pr",
|
|
3046
|
-
description: "Review a single pull request against its linked issue's acceptance criteria, then enable squash auto-merge or comment with findings",
|
|
3047
|
-
disableModelInvocation: true,
|
|
3048
|
-
userInvocable: true,
|
|
3049
|
-
context: "fork",
|
|
3050
|
-
agent: "pr-reviewer",
|
|
3051
|
-
platforms: { cursor: { exclude: true } },
|
|
3052
|
-
instructions: [
|
|
3053
|
-
"# Review Pull Request",
|
|
3072
|
+
"**Goal:** Populate the profile's `## Cross-References` section with",
|
|
3073
|
+
"links to existing artifacts \u2014 companies, software, meetings \u2014 that",
|
|
3074
|
+
"the consuming project already tracks.",
|
|
3054
3075
|
"",
|
|
3055
|
-
"
|
|
3056
|
-
"
|
|
3076
|
+
"**Budget:** No new web searches. No new downstream research issues.",
|
|
3077
|
+
"Read the candidate cross-references, resolve them against the",
|
|
3078
|
+
"configured directories, update the profile.",
|
|
3057
3079
|
"",
|
|
3058
|
-
"
|
|
3080
|
+
"### Steps",
|
|
3059
3081
|
"",
|
|
3060
|
-
"
|
|
3082
|
+
"1. **Read the profile file** referenced in the issue body.",
|
|
3061
3083
|
"",
|
|
3062
|
-
"
|
|
3084
|
+
"2. **Resolve company cross-references.** For each company named in",
|
|
3085
|
+
" the profile's research notes or body text, look for a matching",
|
|
3086
|
+
" file under `<COMPANIES_DIR>/`. If found, link it under",
|
|
3087
|
+
" `## Cross-References > Companies`. If not found, leave a TODO",
|
|
3088
|
+
" comment naming the company \u2014 the invoking project's team decides",
|
|
3089
|
+
" whether to kick off a separate company-profile pipeline.",
|
|
3063
3090
|
"",
|
|
3064
|
-
"
|
|
3065
|
-
"
|
|
3066
|
-
"
|
|
3067
|
-
"4. Compares the diff against each criterion",
|
|
3068
|
-
"5. Verifies PR conventions (title, closing keyword, branch name)",
|
|
3069
|
-
"6. Verifies CI is green",
|
|
3070
|
-
"7. **If all checks pass:** enables squash auto-merge (with `--delete-branch`)",
|
|
3071
|
-
"8. **If any check fails:** posts a findings comment via `gh pr comment`",
|
|
3072
|
-
"9. After merge, verifies the linked issue is closed and closes it if not",
|
|
3073
|
-
"10. Cleans up the local branch after merge",
|
|
3091
|
+
"3. **Resolve software cross-references.** Same pattern against",
|
|
3092
|
+
" `<SOFTWARE_DIR>/`. Link what matches; leave TODOs for what",
|
|
3093
|
+
" doesn't.",
|
|
3074
3094
|
"",
|
|
3075
|
-
"
|
|
3095
|
+
"4. **Resolve meeting cross-references.** For meetings the person",
|
|
3096
|
+
" participated in, look for a matching file under `<MEETINGS_DIR>/`",
|
|
3097
|
+
" by date or slug. Link matches; leave TODOs otherwise.",
|
|
3076
3098
|
"",
|
|
3077
|
-
"
|
|
3078
|
-
"
|
|
3099
|
+
"5. **Do not open downstream issues.** This pipeline emits no",
|
|
3100
|
+
" `company:research`, `research:scope`, or similar issues. Cross-",
|
|
3101
|
+
" references are link-only; downstream research is a separate",
|
|
3102
|
+
" human decision.",
|
|
3079
3103
|
"",
|
|
3080
|
-
"
|
|
3104
|
+
"6. **Commit and push** the updated profile. Close the followup issue.",
|
|
3081
3105
|
"",
|
|
3082
|
-
"
|
|
3083
|
-
"grouped by severity, the action taken, and the final branch / issue state.",
|
|
3106
|
+
"---",
|
|
3084
3107
|
"",
|
|
3085
|
-
"##
|
|
3108
|
+
"## Output Boundaries",
|
|
3086
3109
|
"",
|
|
3087
|
-
"This
|
|
3088
|
-
"
|
|
3089
|
-
"
|
|
3110
|
+
"This agent writes **only** to:",
|
|
3111
|
+
"",
|
|
3112
|
+
"- `<NOTES_DIR>/` \u2014 research-notes files (Phase 1)",
|
|
3113
|
+
"- `<PROFILES_DIR>/` \u2014 person profiles (Phase 2, updated in Phase 3)",
|
|
3114
|
+
"",
|
|
3115
|
+
"The pipeline produces **profiles and notes only**. It does not",
|
|
3116
|
+
"create new companies, software evaluations, meeting notes, or any",
|
|
3117
|
+
"other downstream artifacts \u2014 it only links to those that already",
|
|
3118
|
+
"exist under the configured cross-reference directories. Keep this",
|
|
3119
|
+
"boundary clean so the people-profile pipeline stays generic and",
|
|
3120
|
+
"cheap to run.",
|
|
3121
|
+
"",
|
|
3122
|
+
"---",
|
|
3123
|
+
"",
|
|
3124
|
+
"## Rules",
|
|
3125
|
+
"",
|
|
3126
|
+
"- **One person per session.** Never profile two people back-to-back.",
|
|
3127
|
+
"- **Persist before closing.** Every phase must write its output file",
|
|
3128
|
+
" before closing its issue.",
|
|
3129
|
+
"- **Cite everything.** Profile claims without source citations do not",
|
|
3130
|
+
" belong in the deliverable.",
|
|
3131
|
+
"- **Respect privacy.** Never record private contact details, family",
|
|
3132
|
+
" information, or other non-professional personal data, even when",
|
|
3133
|
+
" encountered in a public source.",
|
|
3134
|
+
"- **Cross-reference, don't duplicate.** Link to existing company,",
|
|
3135
|
+
" software, and meeting artifacts rather than re-describing them.",
|
|
3136
|
+
"- **No downstream issue creation.** Phase 3 emits no new research,",
|
|
3137
|
+
" profile, or requirement issues. Only link.",
|
|
3138
|
+
"- **Refresh, don't fork.** When a profile exists and is past its",
|
|
3139
|
+
" cadence, update in place rather than creating a new slug."
|
|
3090
3140
|
].join("\n")
|
|
3091
3141
|
};
|
|
3092
|
-
var
|
|
3093
|
-
name: "
|
|
3094
|
-
description: "
|
|
3142
|
+
var profilePersonSkill = {
|
|
3143
|
+
name: "profile-person",
|
|
3144
|
+
description: "Kick off a people-profile pipeline. Creates a people:research issue for the given person and dispatches Phase 1 (Research) in the people-profile-analyst agent.",
|
|
3095
3145
|
disableModelInvocation: true,
|
|
3096
3146
|
userInvocable: true,
|
|
3097
3147
|
context: "fork",
|
|
3098
|
-
agent: "
|
|
3148
|
+
agent: "people-profile-analyst",
|
|
3099
3149
|
platforms: { cursor: { exclude: true } },
|
|
3100
3150
|
instructions: [
|
|
3101
|
-
"#
|
|
3151
|
+
"# Profile Person",
|
|
3102
3152
|
"",
|
|
3103
|
-
"
|
|
3104
|
-
"
|
|
3105
|
-
"
|
|
3153
|
+
"Kick off a people-profile pipeline. Creates a `people:research`",
|
|
3154
|
+
"issue carrying the person's name, role, primary affiliation, and",
|
|
3155
|
+
"framing, then dispatches Phase 1 (Research) in the",
|
|
3156
|
+
"people-profile-analyst agent.",
|
|
3106
3157
|
"",
|
|
3107
3158
|
"## Usage",
|
|
3108
3159
|
"",
|
|
3109
|
-
"/
|
|
3110
|
-
"",
|
|
3111
|
-
"## What This Skill Does",
|
|
3112
|
-
"",
|
|
3113
|
-
"### Step 1: Enumerate open PRs",
|
|
3114
|
-
"",
|
|
3115
|
-
"```bash",
|
|
3116
|
-
"gh pr list --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup --limit 50",
|
|
3117
|
-
"```",
|
|
3118
|
-
"",
|
|
3119
|
-
"### Step 2: Filter to eligible PRs",
|
|
3120
|
-
"",
|
|
3121
|
-
"A PR is **eligible** when all of the following hold:",
|
|
3160
|
+
"/profile-person <person-name>",
|
|
3122
3161
|
"",
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
"
|
|
3126
|
-
"
|
|
3127
|
-
"
|
|
3128
|
-
"
|
|
3129
|
-
"
|
|
3162
|
+
"Optional extensions in the issue body:",
|
|
3163
|
+
"- `role: <colleague | customer-contact | vendor-contact |",
|
|
3164
|
+
" partner-contact | industry-expert | connector>` \u2014 override the",
|
|
3165
|
+
" default role inference",
|
|
3166
|
+
"- `company: <name>` \u2014 primary company affiliation if not obvious",
|
|
3167
|
+
" from the name",
|
|
3168
|
+
"- `framing: <text>` \u2014 why this profile was requested and what to learn",
|
|
3169
|
+
"- `slug: <kebab-case>` \u2014 override the derived person slug",
|
|
3170
|
+
"- `refresh_days: <N>` \u2014 override the default 180-day refresh cadence",
|
|
3171
|
+
"- `force: true` \u2014 refresh even if the profile is younger than the",
|
|
3172
|
+
" cadence window",
|
|
3173
|
+
"- `sources: <list>` \u2014 additional authorized sources beyond public web",
|
|
3130
3174
|
"",
|
|
3131
|
-
"
|
|
3132
|
-
"them from this skill \u2014 the individual `/review-pr` invocation handles",
|
|
3133
|
-
"the inline rejection comment when run on a specific PR.",
|
|
3175
|
+
"## Default Paths",
|
|
3134
3176
|
"",
|
|
3135
|
-
"
|
|
3177
|
+
"If the project has no override in `docs/project-context.md` or",
|
|
3178
|
+
"`agentConfig.rules`, outputs land under:",
|
|
3136
3179
|
"",
|
|
3137
|
-
"
|
|
3138
|
-
"
|
|
3139
|
-
"directly:",
|
|
3180
|
+
"- `docs/people/notes/<slug>.notes.md`",
|
|
3181
|
+
"- `docs/people/profiles/<slug>.md`",
|
|
3140
3182
|
"",
|
|
3141
|
-
"-
|
|
3142
|
-
"- Compare diff to acceptance criteria",
|
|
3143
|
-
"- Decide and act (enable auto-merge **or** post findings comment)",
|
|
3144
|
-
"- Verify branch / issue cleanup after merge",
|
|
3183
|
+
"Cross-references are resolved against:",
|
|
3145
3184
|
"",
|
|
3146
|
-
"
|
|
3147
|
-
"
|
|
3185
|
+
"- `docs/companies/profiles/`",
|
|
3186
|
+
"- `docs/software/profiles/`",
|
|
3187
|
+
"- `docs/meetings/`",
|
|
3148
3188
|
"",
|
|
3149
|
-
"
|
|
3189
|
+
"## Steps",
|
|
3150
3190
|
"",
|
|
3151
|
-
"
|
|
3152
|
-
"
|
|
3191
|
+
"1. Create a `people:research` issue with `type:people-profile`,",
|
|
3192
|
+
" `priority:medium`, and `status:ready`. Body must include the",
|
|
3193
|
+
" person's name, selected role, primary company, framing, and any",
|
|
3194
|
+
" overrides.",
|
|
3195
|
+
"2. Execute Phase 1 (Research) of the people-profile-analyst agent.",
|
|
3196
|
+
"3. Phase 1 creates the `people:draft` issue. Phase 2 may create a",
|
|
3197
|
+
" `people:followup` issue. Each downstream issue declares its",
|
|
3198
|
+
" `Depends on:` predecessor.",
|
|
3153
3199
|
"",
|
|
3154
3200
|
"## Output",
|
|
3155
3201
|
"",
|
|
3156
|
-
"
|
|
3157
|
-
"
|
|
3158
|
-
"",
|
|
3159
|
-
"
|
|
3160
|
-
"
|
|
3161
|
-
"
|
|
3162
|
-
" PR #<n>: <verdict>",
|
|
3163
|
-
" ...",
|
|
3164
|
-
"Total processed: <count>",
|
|
3165
|
-
"```",
|
|
3166
|
-
"",
|
|
3167
|
-
"## Failure Handling",
|
|
3168
|
-
"",
|
|
3169
|
-
"Only abort the loop on a fatal error (e.g. `gh` authentication failure,",
|
|
3170
|
-
"network outage). A failed review for an individual PR is not fatal \u2014",
|
|
3171
|
-
"comment on that PR and continue with the next."
|
|
3202
|
+
"- A research-notes file under the project's notes directory",
|
|
3203
|
+
"- A single person profile under the profiles directory",
|
|
3204
|
+
"- Cross-references to existing companies, software, and meetings",
|
|
3205
|
+
" tracked elsewhere in the project",
|
|
3206
|
+
"- This pipeline produces **profiles only** \u2014 it does not create",
|
|
3207
|
+
" companies, software, meetings, or any other downstream artifacts."
|
|
3172
3208
|
].join("\n")
|
|
3173
3209
|
};
|
|
3174
|
-
var
|
|
3175
|
-
name: "
|
|
3176
|
-
description: "
|
|
3177
|
-
|
|
3178
|
-
// and keeping review/merge policy centralised in the pr-reviewer agent
|
|
3179
|
-
// means consumers get consistent behaviour out of the box. Consumers can
|
|
3180
|
-
// still exclude it explicitly via `excludeBundles` if desired.
|
|
3181
|
-
appliesWhen: () => true,
|
|
3210
|
+
var peopleProfileBundle = {
|
|
3211
|
+
name: "people-profile",
|
|
3212
|
+
description: "People research and profiling pipeline: research, draft profile, followup. Opt-in only; domain-neutral; filesystem-durable between phases; cross-references existing companies, software, and meeting notes without creating new downstream issues.",
|
|
3213
|
+
appliesWhen: () => false,
|
|
3182
3214
|
rules: [
|
|
3183
3215
|
{
|
|
3184
|
-
name: "
|
|
3185
|
-
description: "Describes the
|
|
3216
|
+
name: "people-profile-workflow",
|
|
3217
|
+
description: "Describes the 3-phase people-profile pipeline, the people:* label taxonomy, the cross-reference model, and the boundary against downstream research agents.",
|
|
3186
3218
|
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
3187
3219
|
content: [
|
|
3188
|
-
"#
|
|
3189
|
-
"",
|
|
3190
|
-
"Two skills are available, both backed by the same `pr-reviewer`",
|
|
3191
|
-
"sub-agent:",
|
|
3192
|
-
"",
|
|
3193
|
-
"- **`/review-pr <pr-number>`** \u2014 review a single targeted PR.",
|
|
3194
|
-
"- **`/review-prs`** \u2014 loop over every eligible open PR in the",
|
|
3195
|
-
" repository and review each one in turn.",
|
|
3220
|
+
"# People Profile Workflow",
|
|
3196
3221
|
"",
|
|
3197
|
-
"
|
|
3222
|
+
"Use `/profile-person <person-name>` to kick off a person",
|
|
3223
|
+
"research and profiling pipeline. The pipeline runs in up to 3",
|
|
3224
|
+
"phases \u2014 research, draft, followup \u2014 each tracked by its own",
|
|
3225
|
+
"GitHub issue labeled `people:research`, `people:draft`, or",
|
|
3226
|
+
"`people:followup`. All issues carry `type:people-profile`.",
|
|
3198
3227
|
"",
|
|
3199
|
-
"
|
|
3200
|
-
"
|
|
3201
|
-
"
|
|
3202
|
-
"
|
|
3203
|
-
"3. Builds a checklist from the issue's acceptance criteria",
|
|
3204
|
-
"4. Verifies the diff satisfies each criterion and that CI is green",
|
|
3205
|
-
"5. **Enables squash auto-merge** (with `--delete-branch`) when all",
|
|
3206
|
-
" checks pass \u2014 no explicit approval review",
|
|
3207
|
-
"6. **Comments with grouped findings** when any check fails (plain",
|
|
3208
|
-
" `gh pr comment`, not a formal `--request-changes` review)",
|
|
3209
|
-
"7. After a successful merge, verifies the linked issue is closed",
|
|
3210
|
-
" and closes it explicitly if the merge commit did not",
|
|
3211
|
-
"8. Cleans up the local branch after merge",
|
|
3228
|
+
"The pipeline produces **person profiles only**. Cross-references",
|
|
3229
|
+
"to companies, software products, and meeting notes are link-only",
|
|
3230
|
+
"\u2014 the followup phase never creates new downstream research,",
|
|
3231
|
+
"profile, or requirement issues.",
|
|
3212
3232
|
"",
|
|
3213
|
-
"
|
|
3214
|
-
"
|
|
3215
|
-
"
|
|
3216
|
-
"the loop; the reviewer comments and moves on. See the `pr-reviewer`",
|
|
3217
|
-
"agent definition for the full phase-by-phase contract."
|
|
3233
|
+
"See the `people-profile-analyst` agent definition for full",
|
|
3234
|
+
"workflow details, default paths, the person-role taxonomy, the",
|
|
3235
|
+
"refresh cadence rules, and phase-by-phase instructions."
|
|
3218
3236
|
].join("\n"),
|
|
3219
3237
|
platforms: {
|
|
3220
3238
|
cursor: { exclude: true }
|
|
@@ -3222,368 +3240,1384 @@ var prReviewBundle = {
|
|
|
3222
3240
|
tags: ["workflow"]
|
|
3223
3241
|
}
|
|
3224
3242
|
],
|
|
3225
|
-
skills: [
|
|
3226
|
-
subAgents: [
|
|
3243
|
+
skills: [profilePersonSkill],
|
|
3244
|
+
subAgents: [peopleProfileAnalystSubAgent],
|
|
3245
|
+
labels: [
|
|
3246
|
+
{
|
|
3247
|
+
name: "type:people-profile",
|
|
3248
|
+
color: "0E8A16",
|
|
3249
|
+
description: "Work that produces or maintains a person profile or its research notes"
|
|
3250
|
+
},
|
|
3251
|
+
{
|
|
3252
|
+
name: "people:research",
|
|
3253
|
+
color: "C5DEF5",
|
|
3254
|
+
description: "Phase 1: gather public sources about a person into a research-notes file"
|
|
3255
|
+
},
|
|
3256
|
+
{
|
|
3257
|
+
name: "people:draft",
|
|
3258
|
+
color: "BFDADC",
|
|
3259
|
+
description: "Phase 2: write the structured person profile from research notes"
|
|
3260
|
+
},
|
|
3261
|
+
{
|
|
3262
|
+
name: "people:followup",
|
|
3263
|
+
color: "D4C5F9",
|
|
3264
|
+
description: "Phase 3: cross-link the profile to existing companies, software, and meeting notes"
|
|
3265
|
+
}
|
|
3266
|
+
]
|
|
3227
3267
|
};
|
|
3228
3268
|
|
|
3229
|
-
// src/
|
|
3230
|
-
var
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3269
|
+
// src/pnpm/pnpm-workspace.ts
|
|
3270
|
+
var import_path = require("path");
|
|
3271
|
+
var import_projen = require("projen");
|
|
3272
|
+
var MINIMUM_RELEASE_AGE = {
|
|
3273
|
+
ZERO_DAYS: 0,
|
|
3274
|
+
ONE_HOUR: 60,
|
|
3275
|
+
SIX_HOURS: 360,
|
|
3276
|
+
TWELVE_HOURS: 720,
|
|
3277
|
+
ONE_DAY: 1440,
|
|
3278
|
+
TWO_DAYS: 2880,
|
|
3279
|
+
THREE_DAYS: 4320,
|
|
3280
|
+
FOUR_DAYS: 5760,
|
|
3281
|
+
FIVE_DAYS: 7200,
|
|
3282
|
+
SIX_DAYS: 8640,
|
|
3283
|
+
ONE_WEEK: 10080
|
|
3284
|
+
};
|
|
3285
|
+
var PnpmWorkspace = class _PnpmWorkspace extends import_projen.Component {
|
|
3286
|
+
/**
|
|
3287
|
+
* Get the pnpm workspace component of a project. If it does not exist,
|
|
3288
|
+
* return undefined.
|
|
3289
|
+
*
|
|
3290
|
+
* @param project
|
|
3291
|
+
* @returns
|
|
3292
|
+
*/
|
|
3293
|
+
static of(project) {
|
|
3294
|
+
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
3295
|
+
return project.root.components.find(isDefined);
|
|
3296
|
+
}
|
|
3297
|
+
constructor(project, options = {}) {
|
|
3298
|
+
super(project);
|
|
3299
|
+
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
3300
|
+
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
3301
|
+
this.minimumReleaseAge = options.minimumReleaseAge ?? MINIMUM_RELEASE_AGE.ONE_DAY;
|
|
3302
|
+
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
3303
|
+
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
3304
|
+
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
3305
|
+
this.subprojects = options.subprojects ?? [];
|
|
3306
|
+
this.defaultCatalog = options.defaultCatalog;
|
|
3307
|
+
this.namedCatalogs = options.namedCatalogs;
|
|
3308
|
+
project.addPackageIgnore(this.fileName);
|
|
3309
|
+
new import_projen.YamlFile(this.project, this.fileName, {
|
|
3310
|
+
obj: () => {
|
|
3311
|
+
const pnpmConfig = {};
|
|
3312
|
+
const packages = new Array();
|
|
3313
|
+
for (const subproject of project.subprojects) {
|
|
3314
|
+
packages.push((0, import_path.relative)(this.project.outdir, subproject.outdir));
|
|
3315
|
+
}
|
|
3316
|
+
const packageSet = new Set(packages);
|
|
3317
|
+
for (const subprojectPath of this.subprojects) {
|
|
3318
|
+
packageSet.add(subprojectPath);
|
|
3319
|
+
}
|
|
3320
|
+
if (this.subprojects.length > 0) {
|
|
3321
|
+
packages.length = 0;
|
|
3322
|
+
packages.push(...packageSet);
|
|
3323
|
+
}
|
|
3324
|
+
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
3325
|
+
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
3326
|
+
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
3327
|
+
}
|
|
3328
|
+
if (this.onlyBuiltDependencies.length > 0) {
|
|
3329
|
+
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
3330
|
+
}
|
|
3331
|
+
if (this.ignoredBuiltDependencies.length > 0) {
|
|
3332
|
+
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
3333
|
+
}
|
|
3334
|
+
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
3335
|
+
pnpmConfig.catalog = this.defaultCatalog;
|
|
3336
|
+
}
|
|
3337
|
+
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
3338
|
+
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
3339
|
+
}
|
|
3340
|
+
return {
|
|
3341
|
+
...packages.length > 0 ? { packages } : {},
|
|
3342
|
+
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
3343
|
+
};
|
|
3344
|
+
}
|
|
3345
|
+
});
|
|
3346
|
+
}
|
|
3347
|
+
};
|
|
3348
|
+
var MIMIMUM_RELEASE_AGE = MINIMUM_RELEASE_AGE;
|
|
3349
|
+
|
|
3350
|
+
// src/agent/bundles/pnpm.ts
|
|
3351
|
+
var pnpmBundle = {
|
|
3352
|
+
name: "pnpm",
|
|
3353
|
+
description: "PNPM workspace rules and dependency management conventions",
|
|
3354
|
+
appliesWhen: (project) => hasComponent(project, PnpmWorkspace),
|
|
3234
3355
|
rules: [
|
|
3235
3356
|
{
|
|
3236
|
-
name: "
|
|
3237
|
-
description: "
|
|
3238
|
-
scope: AGENT_RULE_SCOPE.
|
|
3357
|
+
name: "pnpm-workspace",
|
|
3358
|
+
description: "PNPM workspace and dependency management conventions",
|
|
3359
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
3360
|
+
filePatterns: ["package.json", "pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
3239
3361
|
content: [
|
|
3240
|
-
"#
|
|
3241
|
-
"",
|
|
3242
|
-
"This project uses Projen to manage configuration and Turborepo to orchestrate builds across the monorepo. Run all commands from the **repository root** unless otherwise noted.",
|
|
3243
|
-
"",
|
|
3244
|
-
"## Synthesizing Projen Configuration",
|
|
3245
|
-
"",
|
|
3246
|
-
"After modifying any file in `projenrc/` or `.projenrc.ts`, regenerate project files:",
|
|
3247
|
-
"",
|
|
3248
|
-
"```sh",
|
|
3249
|
-
"npx projen",
|
|
3250
|
-
"pnpm install",
|
|
3251
|
-
"```",
|
|
3252
|
-
"",
|
|
3253
|
-
"Both steps are required \u2014 `npx projen` regenerates files, `pnpm install` updates the lockfile to match.",
|
|
3254
|
-
"",
|
|
3255
|
-
"## Building",
|
|
3256
|
-
"",
|
|
3257
|
-
"**Full monorepo build** (compile + test + package, all sub-packages via Turborepo):",
|
|
3258
|
-
"",
|
|
3259
|
-
"```sh",
|
|
3260
|
-
"pnpm build:all",
|
|
3261
|
-
"```",
|
|
3262
|
-
"",
|
|
3263
|
-
"**Root project only** (synthesize + compile + lint):",
|
|
3264
|
-
"",
|
|
3265
|
-
"```sh",
|
|
3266
|
-
"pnpm build",
|
|
3267
|
-
"```",
|
|
3268
|
-
"",
|
|
3269
|
-
"**Single sub-package** (compile only):",
|
|
3270
|
-
"",
|
|
3271
|
-
"```sh",
|
|
3272
|
-
"pnpm --filter @codedrifters/<package> compile",
|
|
3273
|
-
"```",
|
|
3274
|
-
"",
|
|
3275
|
-
"Replace `<package>` with `configulator`, `constructs`, or `utils`.",
|
|
3276
|
-
"",
|
|
3277
|
-
"## Testing",
|
|
3278
|
-
"",
|
|
3279
|
-
"**Run tests for a single sub-package:**",
|
|
3280
|
-
"",
|
|
3281
|
-
"```sh",
|
|
3282
|
-
"pnpm --filter @codedrifters/<package> test",
|
|
3283
|
-
"```",
|
|
3284
|
-
"",
|
|
3285
|
-
"This runs ESLint + Vitest for the specified package.",
|
|
3286
|
-
"",
|
|
3287
|
-
"**Run only Vitest (skip lint) in a sub-package:**",
|
|
3288
|
-
"",
|
|
3289
|
-
"```sh",
|
|
3290
|
-
"cd packages/@codedrifters/<package>",
|
|
3291
|
-
"pnpm exec vitest run",
|
|
3292
|
-
"```",
|
|
3293
|
-
"",
|
|
3294
|
-
"**Run a specific test file:**",
|
|
3295
|
-
"",
|
|
3296
|
-
"```sh",
|
|
3297
|
-
"cd packages/@codedrifters/<package>",
|
|
3298
|
-
"pnpm exec vitest run src/path/to/file.test.ts",
|
|
3299
|
-
"```",
|
|
3300
|
-
"",
|
|
3301
|
-
"## Linting",
|
|
3302
|
-
"",
|
|
3303
|
-
"**Lint the root project:**",
|
|
3304
|
-
"",
|
|
3305
|
-
"```sh",
|
|
3306
|
-
"pnpm eslint",
|
|
3307
|
-
"```",
|
|
3308
|
-
"",
|
|
3309
|
-
"**Lint a single sub-package:**",
|
|
3310
|
-
"",
|
|
3311
|
-
"```sh",
|
|
3312
|
-
"pnpm --filter @codedrifters/<package> eslint",
|
|
3313
|
-
"```",
|
|
3314
|
-
"",
|
|
3315
|
-
"## Resetting Build Artifacts",
|
|
3316
|
-
"",
|
|
3317
|
-
"**Reset everything** (all packages + root):",
|
|
3318
|
-
"",
|
|
3319
|
-
"```sh",
|
|
3320
|
-
"pnpm reset:all",
|
|
3321
|
-
"```",
|
|
3362
|
+
"# PNPM Workspace Conventions",
|
|
3322
3363
|
"",
|
|
3323
|
-
"
|
|
3364
|
+
"## Package Management",
|
|
3324
3365
|
"",
|
|
3325
|
-
"
|
|
3326
|
-
"pnpm
|
|
3327
|
-
"
|
|
3366
|
+
"- Use **PNPM** for package management",
|
|
3367
|
+
"- Workspace configuration in `pnpm-workspace.yaml`",
|
|
3368
|
+
"- Dependencies managed through Projen, not directly in `package.json`",
|
|
3369
|
+
"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo",
|
|
3370
|
+
"- Never use published NPM versions of internal packages; always reference the local workspace version",
|
|
3328
3371
|
"",
|
|
3329
|
-
"##
|
|
3372
|
+
"## Dependency Management",
|
|
3330
3373
|
"",
|
|
3331
|
-
"
|
|
3374
|
+
"**DO:**",
|
|
3375
|
+
"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)",
|
|
3376
|
+
"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration",
|
|
3377
|
+
'- Use catalog dependencies when available (e.g., `"aws-cdk-lib@catalog:"`)',
|
|
3378
|
+
"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration",
|
|
3332
3379
|
"",
|
|
3333
|
-
"
|
|
3334
|
-
"
|
|
3335
|
-
"
|
|
3380
|
+
"**DO NOT:**",
|
|
3381
|
+
"- Run `npm install some-package`",
|
|
3382
|
+
"- Run `pnpm add some-package`",
|
|
3383
|
+
"- Run `yarn add some-package`",
|
|
3384
|
+
"- Manually edit `package.json` dependencies",
|
|
3336
3385
|
"",
|
|
3337
|
-
"
|
|
3338
|
-
" - Compile: `pnpm --filter @codedrifters/<package> compile`",
|
|
3339
|
-
" - Test: `pnpm --filter @codedrifters/<package> test`",
|
|
3340
|
-
"",
|
|
3341
|
-
"3. **Changes spanning multiple packages**:",
|
|
3342
|
-
" - Run `pnpm build:all` to validate the full monorepo build",
|
|
3343
|
-
"",
|
|
3344
|
-
"4. **Root-level changes** (projenrc, root config):",
|
|
3345
|
-
" - Run `pnpm build` to validate root synthesis + compilation + lint",
|
|
3346
|
-
"",
|
|
3347
|
-
"## Command Reference",
|
|
3348
|
-
"",
|
|
3349
|
-
"| Task | Command |",
|
|
3350
|
-
"|------|---------|",
|
|
3351
|
-
"| Synthesize projen | `npx projen` |",
|
|
3352
|
-
"| Install deps | `pnpm install` |",
|
|
3353
|
-
"| Full monorepo build | `pnpm build:all` |",
|
|
3354
|
-
"| Root build only | `pnpm build` |",
|
|
3355
|
-
"| Compile one package | `pnpm --filter @codedrifters/<pkg> compile` |",
|
|
3356
|
-
"| Test one package | `pnpm --filter @codedrifters/<pkg> test` |",
|
|
3357
|
-
"| Lint one package | `pnpm --filter @codedrifters/<pkg> eslint` |",
|
|
3358
|
-
"| Lint root | `pnpm eslint` |",
|
|
3359
|
-
"| Reset all artifacts | `pnpm reset:all` |"
|
|
3386
|
+
"Manual package installation creates conflicts with Projen-managed files."
|
|
3360
3387
|
].join("\n"),
|
|
3361
3388
|
tags: ["workflow"]
|
|
3362
|
-
}
|
|
3389
|
+
}
|
|
3390
|
+
]
|
|
3391
|
+
};
|
|
3392
|
+
|
|
3393
|
+
// src/agent/bundles/pr-review.ts
|
|
3394
|
+
var prReviewerSubAgent = {
|
|
3395
|
+
name: "pr-reviewer",
|
|
3396
|
+
description: "Reviews a pull request against its linked issue's acceptance criteria, then enables squash auto-merge or comments with findings",
|
|
3397
|
+
model: AGENT_MODEL.POWERFUL,
|
|
3398
|
+
maxTurns: 40,
|
|
3399
|
+
platforms: { cursor: { exclude: true } },
|
|
3400
|
+
prompt: [
|
|
3401
|
+
"# PR Reviewer Agent",
|
|
3402
|
+
"",
|
|
3403
|
+
"You review a single pull request in **{{repository.owner}}/{{repository.name}}**",
|
|
3404
|
+
"against its linked issue's acceptance criteria, verify code quality and",
|
|
3405
|
+
"convention compliance, and then either enable squash auto-merge or leave",
|
|
3406
|
+
"a review comment with findings. You handle exactly **one PR per session**",
|
|
3407
|
+
"unless invoked from the multi-PR loop skill (`/review-prs`), in which case",
|
|
3408
|
+
"you process each eligible PR in turn.",
|
|
3409
|
+
"",
|
|
3410
|
+
"---",
|
|
3411
|
+
"",
|
|
3412
|
+
...PROJECT_CONTEXT_READER_SECTION,
|
|
3413
|
+
"## Phase 1: Identify the PR",
|
|
3414
|
+
"",
|
|
3415
|
+
"If a PR number was provided in your instructions, use that. Otherwise stop",
|
|
3416
|
+
"and report that you need a PR number \u2014 do not pick one yourself.",
|
|
3417
|
+
"",
|
|
3418
|
+
"## Phase 1.5: Pre-flight Eligibility Filter",
|
|
3419
|
+
"",
|
|
3420
|
+
"Before spending turns on a full review, run a cheap eligibility check:",
|
|
3421
|
+
"",
|
|
3422
|
+
"```bash",
|
|
3423
|
+
"gh pr view <pr-number> --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup",
|
|
3424
|
+
"```",
|
|
3425
|
+
"",
|
|
3426
|
+
"The PR is **eligible** only when **all** of the following hold:",
|
|
3427
|
+
"",
|
|
3428
|
+
'1. `mergeable == "MERGEABLE"` (no merge conflicts).',
|
|
3429
|
+
"2. No **failing** required checks in `statusCheckRollup` \u2014 CI must be",
|
|
3430
|
+
" green or still pending. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, or",
|
|
3431
|
+
" `ERROR` conclusion on a required check disqualifies the PR.",
|
|
3432
|
+
"3. The PR body contains a linked issue via one of the closing keywords:",
|
|
3433
|
+
" `Closes #N`, `Fixes #N`, or `Resolves #N` (case-insensitive).",
|
|
3434
|
+
"",
|
|
3435
|
+
"If **any** check fails, post a short comment explaining the reason and",
|
|
3436
|
+
"stop. Do not proceed to full review.",
|
|
3437
|
+
"",
|
|
3438
|
+
"```bash",
|
|
3439
|
+
"gh pr comment <pr-number> --body '<reason>'",
|
|
3440
|
+
"```",
|
|
3441
|
+
"",
|
|
3442
|
+
"Typical reasons:",
|
|
3443
|
+
"",
|
|
3444
|
+
"- `Not reviewable: merge conflicts \u2014 please rebase onto the default branch.`",
|
|
3445
|
+
"- `Not reviewable: required CI check <name> is failing.`",
|
|
3446
|
+
"- `Not reviewable: PR body is missing a linked issue (Closes #N / Fixes #N / Resolves #N).`",
|
|
3447
|
+
"",
|
|
3448
|
+
"## Phase 2: Gather Context",
|
|
3449
|
+
"",
|
|
3450
|
+
"```bash",
|
|
3451
|
+
"gh pr view <pr-number> --json number,title,body,headRefName,baseRefName,isDraft,state,labels,reviews",
|
|
3452
|
+
"gh pr diff <pr-number>",
|
|
3453
|
+
"gh pr checks <pr-number>",
|
|
3454
|
+
"```",
|
|
3455
|
+
"",
|
|
3456
|
+
"Extract the linked issue number from the PR body using the closing keywords",
|
|
3457
|
+
"(`Closes #N`, `Fixes #N`, or `Resolves #N`) identified in Phase 1.5.",
|
|
3458
|
+
"",
|
|
3459
|
+
"Then fetch the linked issue:",
|
|
3460
|
+
"",
|
|
3461
|
+
"```bash",
|
|
3462
|
+
"gh issue view <issue-number>",
|
|
3463
|
+
"```",
|
|
3464
|
+
"",
|
|
3465
|
+
"## Phase 3: Compare Diff to Acceptance Criteria",
|
|
3466
|
+
"",
|
|
3467
|
+
"Read the issue body for an **Acceptance Criteria** (or equivalent) section.",
|
|
3468
|
+
"Build a checklist from it. For each item:",
|
|
3469
|
+
"",
|
|
3470
|
+
"1. Locate the changes in the diff that satisfy it.",
|
|
3471
|
+
"2. Mark it as `met`, `partial`, or `missing`.",
|
|
3472
|
+
"3. Record the specific files / functions / tests that provide evidence.",
|
|
3473
|
+
"",
|
|
3474
|
+
"Also evaluate:",
|
|
3475
|
+
"",
|
|
3476
|
+
"- **Convention compliance** \u2014 PR title uses a conventional commit prefix,",
|
|
3477
|
+
" body includes a closing keyword, branch name follows project conventions",
|
|
3478
|
+
"- **Test coverage** \u2014 new or changed behavior has tests",
|
|
3479
|
+
"- **CI status** \u2014 `gh pr checks` reports all required checks passing",
|
|
3480
|
+
"- **Scope creep** \u2014 diff stays within the issue's stated scope",
|
|
3481
|
+
"",
|
|
3482
|
+
"## Phase 4: Decide and Act",
|
|
3483
|
+
"",
|
|
3484
|
+
"### If all acceptance criteria are met and CI is green",
|
|
3485
|
+
"",
|
|
3486
|
+
"Enable squash auto-merge with branch deletion. This queues the merge to",
|
|
3487
|
+
"happen once required checks pass; no separate approval review is needed.",
|
|
3488
|
+
"",
|
|
3489
|
+
"```bash",
|
|
3490
|
+
"gh pr merge <pr-number> --auto --squash --delete-branch \\",
|
|
3491
|
+
" --subject '<conventional-commit-title>' \\",
|
|
3492
|
+
" --body '<extended-description>'",
|
|
3493
|
+
"```",
|
|
3494
|
+
"",
|
|
3495
|
+
"The squash-merge subject should follow conventional commit format (e.g.",
|
|
3496
|
+
"`feat(scope): description`). The body should bullet the changes and end",
|
|
3497
|
+
"with `Closes #<issue-number>`.",
|
|
3498
|
+
"",
|
|
3499
|
+
"### If any criterion is missing, partial, or CI is failing",
|
|
3500
|
+
"",
|
|
3501
|
+
"Post a plain comment (not a formal review block) with grouped findings:",
|
|
3502
|
+
"",
|
|
3503
|
+
"```bash",
|
|
3504
|
+
"gh pr comment <pr-number> --body '<grouped findings>'",
|
|
3505
|
+
"```",
|
|
3506
|
+
"",
|
|
3507
|
+
"Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).",
|
|
3508
|
+
"For each blocking finding, cite the unmet acceptance criterion and the",
|
|
3509
|
+
"file or function the gap lives in. Do **not** merge, and do **not** push",
|
|
3510
|
+
"any commits to the PR's branch.",
|
|
3511
|
+
"",
|
|
3512
|
+
"Rationale for using a plain comment rather than `gh pr review",
|
|
3513
|
+
"--request-changes`: it is lighter-weight, doesn't require the author to",
|
|
3514
|
+
"dismiss a formal review, and composes cleanly with the multi-PR loop.",
|
|
3515
|
+
"",
|
|
3516
|
+
"## Phase 5: Branch Cleanup and Issue Closure Verification",
|
|
3517
|
+
"",
|
|
3518
|
+
"Auto-merge may not be immediate. Poll the PR state up to 10 times, waiting",
|
|
3519
|
+
"30 seconds between polls:",
|
|
3520
|
+
"",
|
|
3521
|
+
"```bash",
|
|
3522
|
+
"gh pr view <pr-number> --json state --jq '.state'",
|
|
3523
|
+
"```",
|
|
3524
|
+
"",
|
|
3525
|
+
"- **`MERGED`** \u2014 clean up locally **and** verify the linked issue closed:",
|
|
3526
|
+
" ```bash",
|
|
3527
|
+
" git checkout {{repository.defaultBranch}}",
|
|
3528
|
+
" git pull origin {{repository.defaultBranch}}",
|
|
3529
|
+
" git fetch --prune origin",
|
|
3530
|
+
" git branch -d <branch-name> 2>/dev/null || git branch -D <branch-name> 2>/dev/null || true",
|
|
3531
|
+
" ```",
|
|
3532
|
+
" Then check the linked issue state:",
|
|
3533
|
+
" ```bash",
|
|
3534
|
+
" gh issue view <issue-number> --json state --jq '.state'",
|
|
3535
|
+
" ```",
|
|
3536
|
+
" If the issue is **not** `CLOSED`, close it explicitly (this covers",
|
|
3537
|
+
" malformed or missing closing keywords on the merge commit):",
|
|
3538
|
+
" ```bash",
|
|
3539
|
+
" gh issue close <issue-number> --reason completed",
|
|
3540
|
+
" gh issue comment <issue-number> --body 'PR #<pr-number> merged. Closing issue.'",
|
|
3541
|
+
" ```",
|
|
3542
|
+
"- **`CLOSED` (not merged)** \u2014 leave the branch in place; report the closure.",
|
|
3543
|
+
"- **Still `OPEN`** \u2014 auto-merge is pending; report and stop without deleting.",
|
|
3544
|
+
"",
|
|
3545
|
+
"---",
|
|
3546
|
+
"",
|
|
3547
|
+
"## Output Format",
|
|
3548
|
+
"",
|
|
3549
|
+
"Return a structured report:",
|
|
3550
|
+
"",
|
|
3551
|
+
"```",
|
|
3552
|
+
"PR #<number> \u2014 <title>",
|
|
3553
|
+
"Linked issue: #<issue-number>",
|
|
3554
|
+
"Verdict: AUTO_MERGE_ENABLED | NEEDS_CHANGES | INELIGIBLE | BLOCKED",
|
|
3555
|
+
"",
|
|
3556
|
+
"Acceptance criteria:",
|
|
3557
|
+
" [x] <criterion> \u2014 <evidence>",
|
|
3558
|
+
" [~] <criterion> \u2014 partial: <gap>",
|
|
3559
|
+
" [ ] <criterion> \u2014 missing",
|
|
3560
|
+
"",
|
|
3561
|
+
"Findings:",
|
|
3562
|
+
" - Blocking: <items>",
|
|
3563
|
+
" - Suggested: <items>",
|
|
3564
|
+
" - Nitpick: <items>",
|
|
3565
|
+
"",
|
|
3566
|
+
"Action taken: <enable-auto-merge | commented-on-the-pr | none>",
|
|
3567
|
+
"Branch state: <merged | open | closed>",
|
|
3568
|
+
"Issue state: <closed | open>",
|
|
3569
|
+
"```",
|
|
3570
|
+
"",
|
|
3571
|
+
"---",
|
|
3572
|
+
"",
|
|
3573
|
+
"## Rules",
|
|
3574
|
+
"",
|
|
3575
|
+
"1. **One PR per session** when invoked directly (`/review-pr`). When",
|
|
3576
|
+
" invoked from the multi-PR loop (`/review-prs`), process every eligible",
|
|
3577
|
+
" PR in turn.",
|
|
3578
|
+
"2. **Never merge without a linked issue.** If the PR body has no",
|
|
3579
|
+
" `Closes #N` / `Fixes #N` / `Resolves #N`, comment and stop.",
|
|
3580
|
+
"3. **Never merge with failing CI.** Even if every criterion is met,",
|
|
3581
|
+
" block on red checks.",
|
|
3582
|
+
"4. **Never bypass review conventions.** Always use `--squash`, `--auto`,",
|
|
3583
|
+
" and `--delete-branch` for merges. Do not force-merge.",
|
|
3584
|
+
"5. **Do not implement code.** You review, decide, and orchestrate. If",
|
|
3585
|
+
" the PR needs changes, comment and stop.",
|
|
3586
|
+
"6. **Never push commits to the PR's branch.** If the PR needs changes,",
|
|
3587
|
+
" comment and stop \u2014 do not attempt to fix it yourself. The PR author",
|
|
3588
|
+
" owns the branch; pushing to someone else's branch is out of scope.",
|
|
3589
|
+
"7. **In loop mode (`/review-prs`), never stop early.** If any review",
|
|
3590
|
+
" fails, comment and move to the next PR. Only abort the loop on a",
|
|
3591
|
+
" fatal error (e.g. `gh` auth failure, network outage).",
|
|
3592
|
+
"8. **Follow CLAUDE.md conventions** for all `git` and `gh` operations."
|
|
3593
|
+
].join("\n")
|
|
3594
|
+
};
|
|
3595
|
+
var reviewPrSkill = {
|
|
3596
|
+
name: "review-pr",
|
|
3597
|
+
description: "Review a single pull request against its linked issue's acceptance criteria, then enable squash auto-merge or comment with findings",
|
|
3598
|
+
disableModelInvocation: true,
|
|
3599
|
+
userInvocable: true,
|
|
3600
|
+
context: "fork",
|
|
3601
|
+
agent: "pr-reviewer",
|
|
3602
|
+
platforms: { cursor: { exclude: true } },
|
|
3603
|
+
instructions: [
|
|
3604
|
+
"# Review Pull Request",
|
|
3605
|
+
"",
|
|
3606
|
+
"Run a full PR review against the linked issue's acceptance criteria,",
|
|
3607
|
+
"then either enable squash auto-merge or post a findings comment.",
|
|
3608
|
+
"",
|
|
3609
|
+
"## Usage",
|
|
3610
|
+
"",
|
|
3611
|
+
"/review-pr <pr-number>",
|
|
3612
|
+
"",
|
|
3613
|
+
"## What This Skill Does",
|
|
3614
|
+
"",
|
|
3615
|
+
"1. Runs a pre-flight eligibility filter (mergeable, CI not failing, has linked issue)",
|
|
3616
|
+
"2. Fetches the PR, its diff, CI status, and the linked issue",
|
|
3617
|
+
"3. Builds a checklist from the issue's acceptance criteria",
|
|
3618
|
+
"4. Compares the diff against each criterion",
|
|
3619
|
+
"5. Verifies PR conventions (title, closing keyword, branch name)",
|
|
3620
|
+
"6. Verifies CI is green",
|
|
3621
|
+
"7. **If all checks pass:** enables squash auto-merge (with `--delete-branch`)",
|
|
3622
|
+
"8. **If any check fails:** posts a findings comment via `gh pr comment`",
|
|
3623
|
+
"9. After merge, verifies the linked issue is closed and closes it if not",
|
|
3624
|
+
"10. Cleans up the local branch after merge",
|
|
3625
|
+
"",
|
|
3626
|
+
"## Input",
|
|
3627
|
+
"",
|
|
3628
|
+
"Provide the PR number to review. The skill resolves the linked issue from",
|
|
3629
|
+
"the PR body (`Closes #N` / `Fixes #N` / `Resolves #N`).",
|
|
3630
|
+
"",
|
|
3631
|
+
"## Output",
|
|
3632
|
+
"",
|
|
3633
|
+
"A structured report covering verdict, per-criterion status, findings",
|
|
3634
|
+
"grouped by severity, the action taken, and the final branch / issue state.",
|
|
3635
|
+
"",
|
|
3636
|
+
"## Composability",
|
|
3637
|
+
"",
|
|
3638
|
+
"This skill is generic and can be composed with the `github-workflow`",
|
|
3639
|
+
"bundle. The reviewer never implements code and never pushes to the PR",
|
|
3640
|
+
"branch \u2014 it only reviews, decides, and orchestrates merge or comment."
|
|
3641
|
+
].join("\n")
|
|
3642
|
+
};
|
|
3643
|
+
var reviewPrsSkill = {
|
|
3644
|
+
name: "review-prs",
|
|
3645
|
+
description: "Loop over every eligible open pull request in the repository and review each one through the full pipeline",
|
|
3646
|
+
disableModelInvocation: true,
|
|
3647
|
+
userInvocable: true,
|
|
3648
|
+
context: "fork",
|
|
3649
|
+
agent: "pr-reviewer",
|
|
3650
|
+
platforms: { cursor: { exclude: true } },
|
|
3651
|
+
instructions: [
|
|
3652
|
+
"# Review All Eligible Pull Requests",
|
|
3653
|
+
"",
|
|
3654
|
+
"Run the pr-reviewer pipeline over every eligible open PR in",
|
|
3655
|
+
"**{{repository.owner}}/{{repository.name}}**, one after another, until",
|
|
3656
|
+
"the eligible queue is empty.",
|
|
3657
|
+
"",
|
|
3658
|
+
"## Usage",
|
|
3659
|
+
"",
|
|
3660
|
+
"/review-prs",
|
|
3661
|
+
"",
|
|
3662
|
+
"## What This Skill Does",
|
|
3663
|
+
"",
|
|
3664
|
+
"### Step 1: Enumerate open PRs",
|
|
3665
|
+
"",
|
|
3666
|
+
"```bash",
|
|
3667
|
+
"gh pr list --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup --limit 50",
|
|
3668
|
+
"```",
|
|
3669
|
+
"",
|
|
3670
|
+
"### Step 2: Filter to eligible PRs",
|
|
3671
|
+
"",
|
|
3672
|
+
"A PR is **eligible** when all of the following hold:",
|
|
3673
|
+
"",
|
|
3674
|
+
'1. `state == "OPEN"` (implicit from `gh pr list`).',
|
|
3675
|
+
'2. `mergeable == "MERGEABLE"` (no conflicts).',
|
|
3676
|
+
"3. No required check in `statusCheckRollup` has a failing conclusion",
|
|
3677
|
+
" (`FAILURE`, `TIMED_OUT`, `CANCELLED`, `ERROR`). CI green or still",
|
|
3678
|
+
" pending is fine.",
|
|
3679
|
+
"4. The PR body contains a linked issue (`Closes #N` / `Fixes #N` /",
|
|
3680
|
+
" `Resolves #N`, case-insensitive).",
|
|
3681
|
+
"",
|
|
3682
|
+
"Drop any PR that fails the filter from the queue. Do not comment on",
|
|
3683
|
+
"them from this skill \u2014 the individual `/review-pr` invocation handles",
|
|
3684
|
+
"the inline rejection comment when run on a specific PR.",
|
|
3685
|
+
"",
|
|
3686
|
+
"### Step 3: Process each eligible PR",
|
|
3687
|
+
"",
|
|
3688
|
+
"For every eligible PR, invoke the full pr-reviewer pipeline",
|
|
3689
|
+
"(Phases 1 through 5) as if `/review-pr <number>` had been called",
|
|
3690
|
+
"directly:",
|
|
3691
|
+
"",
|
|
3692
|
+
"- Gather context (diff, checks, linked issue)",
|
|
3693
|
+
"- Compare diff to acceptance criteria",
|
|
3694
|
+
"- Decide and act (enable auto-merge **or** post findings comment)",
|
|
3695
|
+
"- Verify branch / issue cleanup after merge",
|
|
3696
|
+
"",
|
|
3697
|
+
"Continue to the next PR after each one completes. Never stop the loop",
|
|
3698
|
+
"early because a single PR's review failed \u2014 comment and move on.",
|
|
3699
|
+
"",
|
|
3700
|
+
"### Step 4: Stop when the queue is empty",
|
|
3701
|
+
"",
|
|
3702
|
+
"When no eligible PRs remain, emit a final summary listing every PR",
|
|
3703
|
+
"processed and the verdict for each, then stop.",
|
|
3704
|
+
"",
|
|
3705
|
+
"## Output",
|
|
3706
|
+
"",
|
|
3707
|
+
"Per-PR structured report (same shape as `/review-pr`), followed by a",
|
|
3708
|
+
"one-line-per-PR summary at the end:",
|
|
3709
|
+
"",
|
|
3710
|
+
"```",
|
|
3711
|
+
"Summary:",
|
|
3712
|
+
" PR #<n>: <verdict>",
|
|
3713
|
+
" PR #<n>: <verdict>",
|
|
3714
|
+
" ...",
|
|
3715
|
+
"Total processed: <count>",
|
|
3716
|
+
"```",
|
|
3717
|
+
"",
|
|
3718
|
+
"## Failure Handling",
|
|
3719
|
+
"",
|
|
3720
|
+
"Only abort the loop on a fatal error (e.g. `gh` authentication failure,",
|
|
3721
|
+
"network outage). A failed review for an individual PR is not fatal \u2014",
|
|
3722
|
+
"comment on that PR and continue with the next."
|
|
3723
|
+
].join("\n")
|
|
3724
|
+
};
|
|
3725
|
+
var prReviewBundle = {
|
|
3726
|
+
name: "pr-review",
|
|
3727
|
+
description: "Pull request review workflow: verifies PRs against their linked issues' acceptance criteria and orchestrates squash-merge, single or looped over all eligible PRs",
|
|
3728
|
+
// Default-apply: the PR review workflow is safe to include everywhere,
|
|
3729
|
+
// and keeping review/merge policy centralised in the pr-reviewer agent
|
|
3730
|
+
// means consumers get consistent behaviour out of the box. Consumers can
|
|
3731
|
+
// still exclude it explicitly via `excludeBundles` if desired.
|
|
3732
|
+
appliesWhen: () => true,
|
|
3733
|
+
rules: [
|
|
3734
|
+
{
|
|
3735
|
+
name: "pr-review-workflow",
|
|
3736
|
+
description: "Describes the /review-pr and /review-prs skills and their delegation to the pr-reviewer sub-agent",
|
|
3737
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
3738
|
+
content: [
|
|
3739
|
+
"# PR Review Workflow",
|
|
3740
|
+
"",
|
|
3741
|
+
"Two skills are available, both backed by the same `pr-reviewer`",
|
|
3742
|
+
"sub-agent:",
|
|
3743
|
+
"",
|
|
3744
|
+
"- **`/review-pr <pr-number>`** \u2014 review a single targeted PR.",
|
|
3745
|
+
"- **`/review-prs`** \u2014 loop over every eligible open PR in the",
|
|
3746
|
+
" repository and review each one in turn.",
|
|
3747
|
+
"",
|
|
3748
|
+
"The `pr-reviewer` sub-agent:",
|
|
3749
|
+
"",
|
|
3750
|
+
"1. Runs a pre-flight eligibility filter (mergeable, CI not failing,",
|
|
3751
|
+
" has a linked issue). Ineligible PRs get a short comment and are",
|
|
3752
|
+
" skipped.",
|
|
3753
|
+
"2. Fetches the PR, its diff, CI status, and the linked issue",
|
|
3754
|
+
"3. Builds a checklist from the issue's acceptance criteria",
|
|
3755
|
+
"4. Verifies the diff satisfies each criterion and that CI is green",
|
|
3756
|
+
"5. **Enables squash auto-merge** (with `--delete-branch`) when all",
|
|
3757
|
+
" checks pass \u2014 no explicit approval review",
|
|
3758
|
+
"6. **Comments with grouped findings** when any check fails (plain",
|
|
3759
|
+
" `gh pr comment`, not a formal `--request-changes` review)",
|
|
3760
|
+
"7. After a successful merge, verifies the linked issue is closed",
|
|
3761
|
+
" and closes it explicitly if the merge commit did not",
|
|
3762
|
+
"8. Cleans up the local branch after merge",
|
|
3763
|
+
"",
|
|
3764
|
+
"The reviewer **never** implements code and **never** pushes commits",
|
|
3765
|
+
"to a PR's branch \u2014 it only reviews, decides, and orchestrates merge",
|
|
3766
|
+
"or comment. In loop mode, a failed review for one PR never stops",
|
|
3767
|
+
"the loop; the reviewer comments and moves on. See the `pr-reviewer`",
|
|
3768
|
+
"agent definition for the full phase-by-phase contract."
|
|
3769
|
+
].join("\n"),
|
|
3770
|
+
platforms: {
|
|
3771
|
+
cursor: { exclude: true }
|
|
3772
|
+
},
|
|
3773
|
+
tags: ["workflow"]
|
|
3774
|
+
}
|
|
3775
|
+
],
|
|
3776
|
+
skills: [reviewPrSkill, reviewPrsSkill],
|
|
3777
|
+
subAgents: [prReviewerSubAgent]
|
|
3778
|
+
};
|
|
3779
|
+
|
|
3780
|
+
// src/agent/bundles/projen.ts
|
|
3781
|
+
var projenBundle = {
|
|
3782
|
+
name: "projen",
|
|
3783
|
+
description: "Projen conventions, synthesis workflow, .projenrc.ts patterns",
|
|
3784
|
+
appliesWhen: (project) => hasDep(project, "projen"),
|
|
3785
|
+
rules: [
|
|
3786
|
+
{
|
|
3787
|
+
name: "development-commands",
|
|
3788
|
+
description: "Projen development commands for building, testing, linting, and validating changes",
|
|
3789
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
3790
|
+
content: [
|
|
3791
|
+
"# Development Commands",
|
|
3792
|
+
"",
|
|
3793
|
+
"This project uses Projen to manage configuration and Turborepo to orchestrate builds across the monorepo. Run all commands from the **repository root** unless otherwise noted.",
|
|
3794
|
+
"",
|
|
3795
|
+
"## Synthesizing Projen Configuration",
|
|
3796
|
+
"",
|
|
3797
|
+
"After modifying any file in `projenrc/` or `.projenrc.ts`, regenerate project files:",
|
|
3798
|
+
"",
|
|
3799
|
+
"```sh",
|
|
3800
|
+
"npx projen",
|
|
3801
|
+
"pnpm install",
|
|
3802
|
+
"```",
|
|
3803
|
+
"",
|
|
3804
|
+
"Both steps are required \u2014 `npx projen` regenerates files, `pnpm install` updates the lockfile to match.",
|
|
3805
|
+
"",
|
|
3806
|
+
"## Building",
|
|
3807
|
+
"",
|
|
3808
|
+
"**Full monorepo build** (compile + test + package, all sub-packages via Turborepo):",
|
|
3809
|
+
"",
|
|
3810
|
+
"```sh",
|
|
3811
|
+
"pnpm build:all",
|
|
3812
|
+
"```",
|
|
3813
|
+
"",
|
|
3814
|
+
"**Root project only** (synthesize + compile + lint):",
|
|
3815
|
+
"",
|
|
3816
|
+
"```sh",
|
|
3817
|
+
"pnpm build",
|
|
3818
|
+
"```",
|
|
3819
|
+
"",
|
|
3820
|
+
"**Single sub-package** (compile only):",
|
|
3821
|
+
"",
|
|
3822
|
+
"```sh",
|
|
3823
|
+
"pnpm --filter @codedrifters/<package> compile",
|
|
3824
|
+
"```",
|
|
3825
|
+
"",
|
|
3826
|
+
"Replace `<package>` with `configulator`, `constructs`, or `utils`.",
|
|
3827
|
+
"",
|
|
3828
|
+
"## Testing",
|
|
3829
|
+
"",
|
|
3830
|
+
"**Run tests for a single sub-package:**",
|
|
3831
|
+
"",
|
|
3832
|
+
"```sh",
|
|
3833
|
+
"pnpm --filter @codedrifters/<package> test",
|
|
3834
|
+
"```",
|
|
3835
|
+
"",
|
|
3836
|
+
"This runs ESLint + Vitest for the specified package.",
|
|
3837
|
+
"",
|
|
3838
|
+
"**Run only Vitest (skip lint) in a sub-package:**",
|
|
3839
|
+
"",
|
|
3840
|
+
"```sh",
|
|
3841
|
+
"cd packages/@codedrifters/<package>",
|
|
3842
|
+
"pnpm exec vitest run",
|
|
3843
|
+
"```",
|
|
3844
|
+
"",
|
|
3845
|
+
"**Run a specific test file:**",
|
|
3846
|
+
"",
|
|
3847
|
+
"```sh",
|
|
3848
|
+
"cd packages/@codedrifters/<package>",
|
|
3849
|
+
"pnpm exec vitest run src/path/to/file.test.ts",
|
|
3850
|
+
"```",
|
|
3851
|
+
"",
|
|
3852
|
+
"## Linting",
|
|
3853
|
+
"",
|
|
3854
|
+
"**Lint the root project:**",
|
|
3855
|
+
"",
|
|
3856
|
+
"```sh",
|
|
3857
|
+
"pnpm eslint",
|
|
3858
|
+
"```",
|
|
3859
|
+
"",
|
|
3860
|
+
"**Lint a single sub-package:**",
|
|
3861
|
+
"",
|
|
3862
|
+
"```sh",
|
|
3863
|
+
"pnpm --filter @codedrifters/<package> eslint",
|
|
3864
|
+
"```",
|
|
3865
|
+
"",
|
|
3866
|
+
"## Resetting Build Artifacts",
|
|
3867
|
+
"",
|
|
3868
|
+
"**Reset everything** (all packages + root):",
|
|
3869
|
+
"",
|
|
3870
|
+
"```sh",
|
|
3871
|
+
"pnpm reset:all",
|
|
3872
|
+
"```",
|
|
3873
|
+
"",
|
|
3874
|
+
"**Reset root only:**",
|
|
3875
|
+
"",
|
|
3876
|
+
"```sh",
|
|
3877
|
+
"pnpm reset",
|
|
3878
|
+
"```",
|
|
3879
|
+
"",
|
|
3880
|
+
"## Validating Changes Are Complete",
|
|
3881
|
+
"",
|
|
3882
|
+
"After finishing implementation work, validate that changes are correct by running the appropriate commands depending on what was changed:",
|
|
3883
|
+
"",
|
|
3884
|
+
"1. **Projen config changes** (`projenrc/`, `.projenrc.ts`):",
|
|
3885
|
+
" - Run `npx projen` then `pnpm install`",
|
|
3886
|
+
" - Verify no unexpected generated file changes with `git diff`",
|
|
3887
|
+
"",
|
|
3888
|
+
"2. **Source code changes** (in a sub-package):",
|
|
3889
|
+
" - Compile: `pnpm --filter @codedrifters/<package> compile`",
|
|
3890
|
+
" - Test: `pnpm --filter @codedrifters/<package> test`",
|
|
3891
|
+
"",
|
|
3892
|
+
"3. **Changes spanning multiple packages**:",
|
|
3893
|
+
" - Run `pnpm build:all` to validate the full monorepo build",
|
|
3894
|
+
"",
|
|
3895
|
+
"4. **Root-level changes** (projenrc, root config):",
|
|
3896
|
+
" - Run `pnpm build` to validate root synthesis + compilation + lint",
|
|
3897
|
+
"",
|
|
3898
|
+
"## Command Reference",
|
|
3899
|
+
"",
|
|
3900
|
+
"| Task | Command |",
|
|
3901
|
+
"|------|---------|",
|
|
3902
|
+
"| Synthesize projen | `npx projen` |",
|
|
3903
|
+
"| Install deps | `pnpm install` |",
|
|
3904
|
+
"| Full monorepo build | `pnpm build:all` |",
|
|
3905
|
+
"| Root build only | `pnpm build` |",
|
|
3906
|
+
"| Compile one package | `pnpm --filter @codedrifters/<pkg> compile` |",
|
|
3907
|
+
"| Test one package | `pnpm --filter @codedrifters/<pkg> test` |",
|
|
3908
|
+
"| Lint one package | `pnpm --filter @codedrifters/<pkg> eslint` |",
|
|
3909
|
+
"| Lint root | `pnpm eslint` |",
|
|
3910
|
+
"| Reset all artifacts | `pnpm reset:all` |"
|
|
3911
|
+
].join("\n"),
|
|
3912
|
+
tags: ["workflow"]
|
|
3913
|
+
},
|
|
3914
|
+
{
|
|
3915
|
+
name: "agent-rules-customization",
|
|
3916
|
+
description: "How to customize agent rules for this repo via the Projen project definition",
|
|
3917
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
3918
|
+
filePatterns: [
|
|
3919
|
+
"projenrc/**/*.ts",
|
|
3920
|
+
".projenrc.ts",
|
|
3921
|
+
".claude/rules/*.md",
|
|
3922
|
+
".cursor/rules/*.mdc",
|
|
3923
|
+
"CLAUDE.md"
|
|
3924
|
+
],
|
|
3925
|
+
content: [
|
|
3926
|
+
"# Customizing Agent Rules",
|
|
3927
|
+
"",
|
|
3928
|
+
"Agent rules for Claude and Cursor are **generated** by configulator's `AgentConfig` component. The generated output files (`.claude/rules/`, `.cursor/rules/`, `CLAUDE.md`) must not be edited directly \u2014 they are overwritten on every `npx projen` run.",
|
|
3929
|
+
"",
|
|
3930
|
+
"## Adding Repo-Specific Rules",
|
|
3931
|
+
"",
|
|
3932
|
+
"Rules that only apply to this repository should be added to the `agentConfig.rules` array in the Projen project definition (`.projenrc.ts` or `projenrc/*.ts`):",
|
|
3933
|
+
"",
|
|
3934
|
+
"```typescript",
|
|
3935
|
+
"agentConfig: {",
|
|
3936
|
+
" rules: [",
|
|
3937
|
+
" {",
|
|
3938
|
+
" name: 'my-repo-rule',",
|
|
3939
|
+
" description: 'What this rule does',",
|
|
3940
|
+
" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN with filePatterns",
|
|
3941
|
+
" content: '# My Rule\\n\\n- Guideline 1\\n- Guideline 2',",
|
|
3942
|
+
" },",
|
|
3943
|
+
" ],",
|
|
3944
|
+
"}",
|
|
3945
|
+
"```",
|
|
3946
|
+
"",
|
|
3947
|
+
"## Extending Existing Bundle Rules",
|
|
3948
|
+
"",
|
|
3949
|
+
"To append repo-specific content to a rule provided by a configulator bundle (without replacing it), use `agentConfig.ruleExtensions`:",
|
|
3950
|
+
"",
|
|
3951
|
+
"```typescript",
|
|
3952
|
+
"agentConfig: {",
|
|
3953
|
+
" ruleExtensions: {",
|
|
3954
|
+
" 'typescript-conventions': '## Additional Guidelines\\n\\n- My custom guideline',",
|
|
3955
|
+
" },",
|
|
3956
|
+
"}",
|
|
3957
|
+
"```",
|
|
3958
|
+
"",
|
|
3959
|
+
"## After Any Change",
|
|
3960
|
+
"",
|
|
3961
|
+
"Run `npx projen` then `pnpm install` to regenerate the output files."
|
|
3962
|
+
].join("\n"),
|
|
3963
|
+
tags: ["workflow"]
|
|
3964
|
+
},
|
|
3965
|
+
{
|
|
3966
|
+
name: "projen-conventions",
|
|
3967
|
+
description: "Projen configuration patterns and best practices",
|
|
3968
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
3969
|
+
filePatterns: ["projenrc/**/*.ts", ".projenrc.ts"],
|
|
3970
|
+
content: [
|
|
3971
|
+
"# Projen Conventions",
|
|
3972
|
+
"",
|
|
3973
|
+
"## Configuration Management",
|
|
3974
|
+
"",
|
|
3975
|
+
"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)",
|
|
3976
|
+
"- Edit Projen configuration in:",
|
|
3977
|
+
" - `.projenrc.ts` (root)",
|
|
3978
|
+
" - `projenrc/*.ts` (package-specific)",
|
|
3979
|
+
"- After making Projen changes, run `npx projen` to synthesize",
|
|
3980
|
+
"",
|
|
3981
|
+
"## Workspace Dependencies",
|
|
3982
|
+
"",
|
|
3983
|
+
"When adding dependencies between packages in a monorepo:",
|
|
3984
|
+
"",
|
|
3985
|
+
'- Use the workspace protocol: `project.addDeps("@org/sibling-pkg@workspace:*")`',
|
|
3986
|
+
"- This ensures the local version is always resolved, not a registry version",
|
|
3987
|
+
'- For dev dependencies: `project.addDevDeps("@org/sibling-pkg@workspace:*")`',
|
|
3988
|
+
"",
|
|
3989
|
+
"## The `configureMyProject` Pattern",
|
|
3990
|
+
"",
|
|
3991
|
+
"Each package should expose a `configureMyProject(options)` factory function that creates and configures its Projen project:",
|
|
3992
|
+
"",
|
|
3993
|
+
"```typescript",
|
|
3994
|
+
"export function configureMyProject(",
|
|
3995
|
+
" options: MyProjectOptions,",
|
|
3996
|
+
"): TypeScriptProject {",
|
|
3997
|
+
" const project = new TypeScriptProject({",
|
|
3998
|
+
" ...options,",
|
|
3999
|
+
" // package-specific defaults",
|
|
4000
|
+
" });",
|
|
4001
|
+
"",
|
|
4002
|
+
" // Attach components, configure rules, etc.",
|
|
4003
|
+
" return project;",
|
|
4004
|
+
"}",
|
|
4005
|
+
"```",
|
|
4006
|
+
"",
|
|
4007
|
+
"This pattern keeps `.projenrc.ts` clean and makes package configuration reusable and testable.",
|
|
4008
|
+
"",
|
|
4009
|
+
"## Custom Projen Components",
|
|
4010
|
+
"",
|
|
4011
|
+
"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:",
|
|
4012
|
+
"",
|
|
4013
|
+
"```typescript",
|
|
4014
|
+
"export class MyComponent extends Component {",
|
|
4015
|
+
" public static of(project: Project): MyComponent | undefined {",
|
|
4016
|
+
" const isDefined = (c: Component): c is MyComponent =>",
|
|
4017
|
+
" c instanceof MyComponent;",
|
|
4018
|
+
" return project.components.find(isDefined);",
|
|
4019
|
+
" }",
|
|
4020
|
+
"",
|
|
4021
|
+
" constructor(project: Project, options: MyComponentOptions) {",
|
|
4022
|
+
" super(project);",
|
|
4023
|
+
" // Implementation",
|
|
4024
|
+
" }",
|
|
4025
|
+
"}",
|
|
4026
|
+
"```",
|
|
4027
|
+
"",
|
|
4028
|
+
"## Component Authoring",
|
|
4029
|
+
"",
|
|
4030
|
+
"- Export project types and utilities from `index.ts`",
|
|
4031
|
+
"- Follow Projen's component lifecycle patterns",
|
|
4032
|
+
"- Use `merge` from `ts-deepmerge` for deep merging configuration objects",
|
|
4033
|
+
"- Components should be reusable and configurable; use TypeScript interfaces for component options",
|
|
4034
|
+
"- Provide sensible defaults while allowing customization",
|
|
4035
|
+
"- Document public APIs with minimal JSDoc; put extended documentation in markdown",
|
|
4036
|
+
"",
|
|
4037
|
+
"## Dependencies",
|
|
4038
|
+
"",
|
|
4039
|
+
"- Dependencies managed through Projen configuration, not directly in `package.json`",
|
|
4040
|
+
'- Use catalog dependencies when available (e.g., `"projen": "catalog:"`)',
|
|
4041
|
+
"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)",
|
|
4042
|
+
'- Use workspace protocol for internal packages: `"@org/pkg@workspace:*"`'
|
|
4043
|
+
].join("\n"),
|
|
4044
|
+
tags: ["workflow"]
|
|
4045
|
+
}
|
|
4046
|
+
]
|
|
4047
|
+
};
|
|
4048
|
+
|
|
4049
|
+
// src/agent/bundles/requirements-analyst.ts
|
|
4050
|
+
var requirementsAnalystSubAgent = {
|
|
4051
|
+
name: "requirements-analyst",
|
|
4052
|
+
description: "Discovers requirement gaps from BCM model docs, competitive analysis, product docs, and meeting extracts. Produces scan reports and proposals for the downstream requirements-writer agent. Runs through a 3-phase pipeline (scan \u2192 draft \u2192 trace), one phase per session, tracked by req:* GitHub issue labels.",
|
|
4053
|
+
model: AGENT_MODEL.POWERFUL,
|
|
4054
|
+
maxTurns: 80,
|
|
4055
|
+
platforms: { cursor: { exclude: true } },
|
|
4056
|
+
prompt: [
|
|
4057
|
+
"# Requirements Analyst Agent",
|
|
4058
|
+
"",
|
|
4059
|
+
"Dedicated agent loop for discovering requirement gaps from BCM (Business",
|
|
4060
|
+
"Capability Model) documents, product docs, and competitive analysis \u2014 then",
|
|
4061
|
+
"creating well-formed requirement issues for the downstream",
|
|
4062
|
+
"requirements-writer (BCM writer) agent to draft. Designed for scheduled",
|
|
4063
|
+
"execution downstream of the BCM writer and company research agents.",
|
|
4064
|
+
"",
|
|
4065
|
+
"Follow your project's shared agent conventions (`AGENTS.md`,",
|
|
4066
|
+
"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.",
|
|
4067
|
+
"",
|
|
4068
|
+
"---",
|
|
4069
|
+
"",
|
|
4070
|
+
...PROJECT_CONTEXT_MAINTAINER_SECTION,
|
|
4071
|
+
"## Design Principles",
|
|
4072
|
+
"",
|
|
4073
|
+
"1. **Discover, don't write.** This agent identifies *what requirements are",
|
|
4074
|
+
" missing*. The requirements-writer skill writes the actual documents. The",
|
|
4075
|
+
" boundary keeps this agent fast and the requirements-writer authoritative.",
|
|
4076
|
+
"2. **Trace everything.** Every discovered gap links to the source that",
|
|
4077
|
+
" revealed it (a BCM model doc, competitive analysis, product doc, or",
|
|
4078
|
+
" meeting extract).",
|
|
4079
|
+
"3. **Respect the taxonomy.** Route every discovered requirement to the",
|
|
4080
|
+
" correct BCM category (FR, BR, NFR, SEC, DR, INT, OPS, UX, MT, ADR, TR)",
|
|
4081
|
+
" using the disambiguation rules in the requirements-writer skill.",
|
|
4082
|
+
"4. **Deduplicate.** Before creating an issue, check whether a requirement",
|
|
4083
|
+
" already exists or an issue is already open for it.",
|
|
4084
|
+
"",
|
|
4085
|
+
"---",
|
|
4086
|
+
"",
|
|
4087
|
+
"## State Machine Overview",
|
|
4088
|
+
"",
|
|
4089
|
+
"Requirements synthesis flows through **3 phases**:",
|
|
4090
|
+
"",
|
|
4091
|
+
"```",
|
|
4092
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
4093
|
+
"\u2502 1. SCAN \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 2. DRAFT \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 3. TRACE \u2502",
|
|
4094
|
+
"\u2502 Read docs, \u2502 \u2502 Write gap \u2502 \u2502 Create GH \u2502",
|
|
4095
|
+
"\u2502 identify \u2502 \u2502 report with \u2502 \u2502 issues and \u2502",
|
|
4096
|
+
"\u2502 gaps, check \u2502 \u2502 requirement \u2502 \u2502 update src \u2502",
|
|
4097
|
+
"\u2502 for dupes \u2502 \u2502 proposals \u2502 \u2502 docs with \u2502",
|
|
4098
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 traceability\u2502",
|
|
4099
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
4100
|
+
"```",
|
|
4101
|
+
"",
|
|
4102
|
+
"**Issue labels encode the phase:**",
|
|
4103
|
+
"",
|
|
4104
|
+
"| Label | Phase | Session work |",
|
|
4105
|
+
"|-------|-------|-------------|",
|
|
4106
|
+
"| `req:scan` | 1. Scan | Read source docs, identify potential requirement gaps, check against existing requirements and open issues, write deduplicated scan report |",
|
|
4107
|
+
"| `req:draft` | 2. Draft | Write gap report with proposed requirements |",
|
|
4108
|
+
"| `req:trace` | 3. Trace | Create GitHub issues for each proposed requirement and update source documents with traceability notes |",
|
|
4109
|
+
"",
|
|
4110
|
+
"All issues also carry `type:requirement` and a `status:*` label.",
|
|
4111
|
+
"",
|
|
4112
|
+
"**Issue count per scan cycle:** 1 scan + 1 draft + 1 trace = **3 sessions**.",
|
|
4113
|
+
"",
|
|
4114
|
+
"**Shortened paths:**",
|
|
4115
|
+
"- No gaps found after scan \u2192 skip draft and trace \u2192 **1 session**",
|
|
4116
|
+
"- No source docs need traceability updates \u2192 still **3 sessions** (trace",
|
|
4117
|
+
" handles both issue creation and doc updates)",
|
|
4118
|
+
"",
|
|
4119
|
+
"---",
|
|
4120
|
+
"",
|
|
4121
|
+
"## Configurable Paths",
|
|
4122
|
+
"",
|
|
4123
|
+
"Projects adopting this bundle must define these paths in their agent",
|
|
4124
|
+
"configuration (`agentConfig.rules` extension or project-level docs):",
|
|
4125
|
+
"",
|
|
4126
|
+
"| Placeholder | Meaning | Typical value |",
|
|
4127
|
+
"|-------------|---------|---------------|",
|
|
4128
|
+
"| `<BCM_DOCS_ROOT>` | Root of BCM model docs (capability models) | `src/content/docs/concepts/` |",
|
|
4129
|
+
"| `<COMPETITIVE_ROOT>` | Competitive analysis docs | `src/content/docs/business-strategy/competitive/` |",
|
|
4130
|
+
"| `<PRODUCT_ROOT>` | Product roadmap / entity taxonomy | `src/content/docs/product/` |",
|
|
4131
|
+
"| `<MEETINGS_ROOT>` | Meeting extracts | `src/content/docs/research/meetings/` |",
|
|
4132
|
+
"| `<RESEARCH_REQUIREMENTS_ROOT>` | Scan reports and proposals | `src/content/docs/research/requirements/` |",
|
|
4133
|
+
"| `<REQUIREMENTS_ROOT>` | Final requirement documents (owned by requirements-writer) | `src/content/docs/requirements/` |",
|
|
4134
|
+
"| `<PREFIX>` | Project-specific requirement ID prefix | e.g. `VRTX`, `ACME` |",
|
|
4135
|
+
"",
|
|
4136
|
+
"If your project stores these in different locations, substitute accordingly",
|
|
4137
|
+
"wherever the phase instructions reference a path.",
|
|
4138
|
+
"",
|
|
4139
|
+
"---",
|
|
4140
|
+
"",
|
|
4141
|
+
"## Agent Loop",
|
|
4142
|
+
"",
|
|
4143
|
+
"Run this loop exactly once per session. Never start a second issue.",
|
|
4144
|
+
"",
|
|
4145
|
+
"1. Claim one open `type:requirement` issue using phase priority:",
|
|
4146
|
+
" `req:scan` > `req:draft` > `req:trace`.",
|
|
4147
|
+
"2. Transition `status:ready` \u2192 `status:in-progress` and create the branch",
|
|
4148
|
+
" per your project's branch-naming convention.",
|
|
4149
|
+
"3. Execute the phase handler that matches the issue's `req:*` label.",
|
|
4150
|
+
"4. Commit, push, open a PR (if applicable), and close the issue per your",
|
|
4151
|
+
" project's PR workflow.",
|
|
4152
|
+
"",
|
|
4153
|
+
"---",
|
|
4154
|
+
"",
|
|
4155
|
+
"## Phase 1: Scan (`req:scan`)",
|
|
4156
|
+
"",
|
|
4157
|
+
"**Goal:** Read source documents, identify where requirements are missing,",
|
|
4158
|
+
"incomplete, or contradictory, then check each potential gap against existing",
|
|
4159
|
+
"requirements and open issues to eliminate duplicates. Produces a single",
|
|
4160
|
+
"deduplicated scan report.",
|
|
4161
|
+
"",
|
|
4162
|
+
"**Budget:** Reading source docs + reading requirement registries + searching",
|
|
4163
|
+
"issues. Write one deduplicated scan output file.",
|
|
4164
|
+
"",
|
|
4165
|
+
"### Scan Sources",
|
|
4166
|
+
"",
|
|
4167
|
+
"The issue specifies which source(s) to scan. Common scan scopes:",
|
|
4168
|
+
"",
|
|
4169
|
+
"| Scope | What to read | What to look for |",
|
|
4170
|
+
"|-------|-------------|-----------------|",
|
|
4171
|
+
"| **BCM model doc** | One `{PREFIX}-NNN` doc under `<BCM_DOCS_ROOT>` | The doc's project-relevance section (commonly `## <Project> Relevance` or `## Strategic Implications`) \u2014 gaps where capabilities exist but no FR/BR/INT addresses them. Use `docs/project-context.md` to judge what is relevant. |",
|
|
4172
|
+
"| **Competitive analysis** | One `comp-*.md` doc under `<COMPETITIVE_ROOT>` | Feature comparison gaps \u2014 competitor features the product lacks requirements for |",
|
|
4173
|
+
"| **Product roadmap** | `<PRODUCT_ROOT>/prioritized-feature-roadmap.md` | Roadmap items without corresponding FRs |",
|
|
4174
|
+
"| **Entity taxonomy** | `<PRODUCT_ROOT>/entity-taxonomy.md` | Entities without CRUD requirements (FR), data requirements (DR), or security requirements (SEC) |",
|
|
4175
|
+
"| **Meeting extract** | `<MEETINGS_ROOT>/meeting-*.extract.md` | Requirements identified but not yet formalized |",
|
|
4176
|
+
"",
|
|
4177
|
+
"### Steps",
|
|
4178
|
+
"",
|
|
4179
|
+
"1. **Read the source documents** specified in the issue.",
|
|
4180
|
+
"",
|
|
4181
|
+
"2. **Identify potential gaps.** For each potential missing requirement:",
|
|
4182
|
+
" - Classify into the correct BCM category (FR, BR, NFR, SEC, DR, INT,",
|
|
4183
|
+
" OPS, UX, MT, ADR, TR)",
|
|
4184
|
+
" - Apply the disambiguation rules from the requirements-writer skill",
|
|
4185
|
+
" - Note the source that revealed the gap",
|
|
4186
|
+
" - Estimate priority based on the source context",
|
|
4187
|
+
"",
|
|
4188
|
+
"3. **Read the requirements registry.** Scan `_index.md` files in each",
|
|
4189
|
+
" `<REQUIREMENTS_ROOT>/<category>/` directory to know what already exists.",
|
|
4190
|
+
"",
|
|
4191
|
+
"4. **Search for existing issues.** For each potential gap, search open issues:",
|
|
4192
|
+
" ```bash",
|
|
4193
|
+
' gh issue list --label "type:requirement" --state open \\',
|
|
4194
|
+
" --json number,title --limit 100",
|
|
4195
|
+
" ```",
|
|
4196
|
+
"",
|
|
4197
|
+
"5. **Classify each gap:**",
|
|
4198
|
+
" - **New** \u2014 no existing requirement or open issue covers this",
|
|
4199
|
+
" - **Duplicate** \u2014 an existing requirement already addresses this",
|
|
4200
|
+
" - **In progress** \u2014 an open issue already targets this",
|
|
4201
|
+
" - **Partial** \u2014 existing requirement partially covers this; note the gap",
|
|
4202
|
+
"",
|
|
4203
|
+
"6. **Write the deduplicated scan report** to:",
|
|
4204
|
+
" ```",
|
|
4205
|
+
" <RESEARCH_REQUIREMENTS_ROOT>/req-scan-<scope>-<YYYY-MM-DD>.md",
|
|
4206
|
+
" ```",
|
|
4207
|
+
"",
|
|
4208
|
+
" Format:",
|
|
4209
|
+
" ```markdown",
|
|
4210
|
+
" ---",
|
|
4211
|
+
' title: "Requirements Scan: <scope>"',
|
|
4212
|
+
" date: YYYY-MM-DD",
|
|
4213
|
+
" parent_issue: <N>",
|
|
4214
|
+
" status: complete",
|
|
4215
|
+
" ---",
|
|
4216
|
+
"",
|
|
4217
|
+
" # Requirements Scan: <scope>",
|
|
4218
|
+
"",
|
|
4219
|
+
" ## Source Documents Reviewed",
|
|
4220
|
+
" - <path> \u2014 <brief description>",
|
|
4221
|
+
"",
|
|
4222
|
+
" ## Existing Requirements Checked",
|
|
4223
|
+
" - <category>: <count> existing docs, <count> open issues",
|
|
4224
|
+
"",
|
|
4225
|
+
" ## Identified Gaps (New)",
|
|
4226
|
+
" ### Gap 1: <Title>",
|
|
4227
|
+
" - **Category:** FR / BR / NFR / SEC / DR / INT / OPS / UX / MT / ADR / TR",
|
|
4228
|
+
" - **Source:** <path to doc + section that revealed this gap>",
|
|
4229
|
+
" - **Priority:** High / Normal / Low",
|
|
4230
|
+
" - **Rationale:** <why this requirement is needed>",
|
|
4231
|
+
" - **Duplicate check:** No existing requirement or open issue found",
|
|
4232
|
+
" - **Proposed scope:** <1-2 sentences on what the requirement should cover>",
|
|
4233
|
+
"",
|
|
4234
|
+
" ## Already Covered",
|
|
4235
|
+
" <list of potential gaps that turned out to already have requirements>",
|
|
4236
|
+
"",
|
|
4237
|
+
" ## In Progress",
|
|
4238
|
+
" <gaps that already have open issues \u2014 include issue numbers>",
|
|
4239
|
+
"",
|
|
4240
|
+
" ## Ambiguous / Needs Human Decision",
|
|
4241
|
+
" <gaps where the correct category or scope is unclear>",
|
|
4242
|
+
" ```",
|
|
4243
|
+
"",
|
|
4244
|
+
"7. **Create downstream issues based on findings:**",
|
|
4245
|
+
" - If any new gaps were identified \u2192 create `req:draft` issue",
|
|
4246
|
+
" (blocked on this issue via `Depends on: #N`).",
|
|
4247
|
+
" - If **no gaps** were found \u2192 stop (no further phases needed). Comment",
|
|
4248
|
+
" on the issue noting that no gaps were identified, and proceed directly",
|
|
4249
|
+
" to commit and push. The scan issue will be marked done with no",
|
|
4250
|
+
" downstream work needed.",
|
|
4251
|
+
"",
|
|
4252
|
+
"8. **Commit and push.**",
|
|
4253
|
+
"",
|
|
4254
|
+
"---",
|
|
4255
|
+
"",
|
|
4256
|
+
"## Phase 2: Draft (`req:draft`)",
|
|
4257
|
+
"",
|
|
4258
|
+
"**Goal:** Expand each identified gap into a requirement proposal with enough",
|
|
4259
|
+
"detail for the requirements-writer to produce a full document.",
|
|
4260
|
+
"",
|
|
4261
|
+
"**Budget:** No web searches. Reading + writing.",
|
|
4262
|
+
"",
|
|
4263
|
+
"### Steps",
|
|
4264
|
+
"",
|
|
4265
|
+
"1. **Read the scan report** from Phase 1.",
|
|
4266
|
+
"",
|
|
4267
|
+
"2. **For each gap**, write a detailed proposal:",
|
|
4268
|
+
"",
|
|
4269
|
+
" ```markdown",
|
|
4270
|
+
" ## Proposed: <PREFIX>-<NNN> \u2014 <Title>",
|
|
4271
|
+
"",
|
|
4272
|
+
" **Category:** <FR/BR/NFR/SEC/DR/INT/OPS/UX/MT/ADR/TR>",
|
|
4273
|
+
" **Priority:** <High/Normal/Low>",
|
|
4274
|
+
" **Source:** <document path and section>",
|
|
4275
|
+
"",
|
|
4276
|
+
" ### Summary",
|
|
4277
|
+
" <2-3 sentences describing what the requirement should capture>",
|
|
4278
|
+
"",
|
|
4279
|
+
" ### Draft Acceptance Criteria",
|
|
4280
|
+
" - [ ] <testable criterion 1>",
|
|
4281
|
+
" - [ ] <testable criterion 2>",
|
|
4282
|
+
" - [ ] <testable criterion 3>",
|
|
4283
|
+
"",
|
|
4284
|
+
" ### Traceability",
|
|
4285
|
+
" - **Implements:** <BR or parent requirement if applicable>",
|
|
4286
|
+
" - **Related:** <existing requirements that interact with this one>",
|
|
4287
|
+
" - **Source:** <BCM doc, competitive analysis, or meeting that revealed",
|
|
4288
|
+
" the gap \u2014 use a markdown link. If the source is a meeting note, the",
|
|
4289
|
+
" downstream requirement doc must include the same meeting as a link in",
|
|
4290
|
+
" its Traceability `Related:` list.>",
|
|
4291
|
+
"",
|
|
4292
|
+
" ### Decision Authority",
|
|
4293
|
+
' <"Direct write" for BR/FR/NFR/SEC/UX, or "Proposed \u2014 needs human',
|
|
4294
|
+
' decision" for ADR/TR, or "Mixed \u2014 defer technology choices" for',
|
|
4295
|
+
" DR/MT/INT/OPS>",
|
|
4296
|
+
"",
|
|
4297
|
+
" ### Notes for Requirements Writer",
|
|
4298
|
+
" <any context the writer should know \u2014 related ADRs, existing partial",
|
|
4299
|
+
" coverage, relevant competitive features>",
|
|
4300
|
+
" ```",
|
|
4301
|
+
"",
|
|
4302
|
+
"3. **Write the proposals** to:",
|
|
4303
|
+
" ```",
|
|
4304
|
+
" <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<YYYY-MM-DD>.md",
|
|
4305
|
+
" ```",
|
|
4306
|
+
"",
|
|
4307
|
+
"4. **Determine next sequence numbers.** Check each target category",
|
|
4308
|
+
" directory under `<REQUIREMENTS_ROOT>/<category>/` to find the next",
|
|
4309
|
+
" available `NNN` for each proposed requirement.",
|
|
4310
|
+
"",
|
|
4311
|
+
"5. **Create the `req:trace` issue** blocked on this draft issue.",
|
|
4312
|
+
"",
|
|
4313
|
+
"6. **Commit and push.**",
|
|
4314
|
+
"",
|
|
4315
|
+
"---",
|
|
4316
|
+
"",
|
|
4317
|
+
"## Phase 3: Trace (`req:trace`)",
|
|
4318
|
+
"",
|
|
4319
|
+
"**Goal:** Create GitHub issues for each proposed requirement and update",
|
|
4320
|
+
"source documents with traceability notes indicating that requirement issues",
|
|
4321
|
+
"were created.",
|
|
4322
|
+
"",
|
|
4323
|
+
"**Budget:** No web searches. Issue creation + minor edits to source",
|
|
4324
|
+
"documents.",
|
|
4325
|
+
"",
|
|
4326
|
+
"### Steps",
|
|
4327
|
+
"",
|
|
4328
|
+
"1. **Read the proposals** from Phase 2.",
|
|
4329
|
+
"",
|
|
4330
|
+
"2. **Create requirement issues.** For each proposal:",
|
|
4331
|
+
"",
|
|
4332
|
+
" All `type:requirement` issues default to `priority:medium` (override",
|
|
4333
|
+
" only if the proposal's priority was explicitly High or Low).",
|
|
4334
|
+
"",
|
|
4335
|
+
" ```bash",
|
|
4336
|
+
" gh issue create \\",
|
|
4337
|
+
' --title "docs(<category>): <PREFIX>-<NNN> \u2014 <title>" \\',
|
|
4338
|
+
' --label "type:requirement" --label "status:ready" --label "priority:medium" \\',
|
|
4339
|
+
' --body "## Objective',
|
|
4340
|
+
" Write <PREFIX>-<NNN> \u2014 <title>.",
|
|
4341
|
+
"",
|
|
4342
|
+
" ## Context",
|
|
4343
|
+
" - **Gap identified by:** requirements scan of <source>",
|
|
4344
|
+
" - **Proposals file:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md",
|
|
4345
|
+
"",
|
|
4346
|
+
" ## Inputs",
|
|
4347
|
+
" - **Depends on:** (none)",
|
|
4348
|
+
" - **Read:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md, <source docs>",
|
|
4349
|
+
"",
|
|
4350
|
+
" ## Acceptance Criteria",
|
|
4351
|
+
" - [ ] Requirement document follows <category> template",
|
|
4352
|
+
" - [ ] Traceability links to source BCM/competitive/product doc",
|
|
4353
|
+
" - [ ] Registry index updated",
|
|
4354
|
+
" - [ ] Decision authority rules followed (direct write vs. proposed)",
|
|
4355
|
+
"",
|
|
4356
|
+
" ## Scope Size",
|
|
4357
|
+
" small",
|
|
4358
|
+
"",
|
|
4359
|
+
" ## Output Path",
|
|
4360
|
+
' <REQUIREMENTS_ROOT>/<category>/<PREFIX>-<NNN>-<slug>.md"',
|
|
4361
|
+
" ```",
|
|
4362
|
+
"",
|
|
4363
|
+
"3. **Update source documents.** In each BCM model doc or competitive",
|
|
4364
|
+
" analysis that was scanned, add a note in the project-relevance /",
|
|
4365
|
+
" strategic-implications section (whichever heading the source doc uses)",
|
|
4366
|
+
" indicating that a requirement issue was created:",
|
|
4367
|
+
"",
|
|
4368
|
+
" ```markdown",
|
|
4369
|
+
" - Gap addressed: see [<PREFIX>-<NNN>](<relative path to requirement doc>)",
|
|
4370
|
+
" (issue #<N>)",
|
|
4371
|
+
" ```",
|
|
4372
|
+
"",
|
|
4373
|
+
"4. **Comment on the scan issue** with a summary of all issues created and",
|
|
4374
|
+
" all docs updated.",
|
|
4375
|
+
"",
|
|
4376
|
+
"5. **Commit and push.**",
|
|
4377
|
+
"",
|
|
4378
|
+
"---",
|
|
4379
|
+
"",
|
|
4380
|
+
"## Coordination with Other Agents",
|
|
4381
|
+
"",
|
|
4382
|
+
"| Direction | Agent | What |",
|
|
4383
|
+
"|-----------|-------|------|",
|
|
4384
|
+
"| Upstream | BCM Writer | Scans capability-model docs for project-relevance gaps (judged against `docs/project-context.md`) |",
|
|
4385
|
+
"| Upstream | Company Research | Scans competitive analysis for feature comparison gaps |",
|
|
4386
|
+
"| Upstream | Meeting Analyst | Scans meeting extracts for requirement proposals |",
|
|
4387
|
+
"| Downstream | Requirements Writer (BCM Writer) | Creates `type:requirement` issues for the skill to draft |",
|
|
4388
|
+
"",
|
|
4389
|
+
"**File boundaries:** Writes to `<RESEARCH_REQUIREMENTS_ROOT>/req-*.md` and",
|
|
4390
|
+
"minor traceability edits to `<BCM_DOCS_ROOT>` and `<COMPETITIVE_ROOT>`.",
|
|
4391
|
+
"Never writes to `<REQUIREMENTS_ROOT>/` \u2014 that is owned by the",
|
|
4392
|
+
"requirements-writer agent.",
|
|
4393
|
+
"",
|
|
4394
|
+
"---",
|
|
4395
|
+
"",
|
|
4396
|
+
"## Blocked Issues",
|
|
4397
|
+
"",
|
|
4398
|
+
"Additional block reasons specific to requirements synthesis:",
|
|
4399
|
+
"- Source document has unresolved contradictions",
|
|
4400
|
+
"- Category classification is ambiguous (needs human disambiguation)",
|
|
4401
|
+
"- Dependent BCM documents are still in draft with placeholder content",
|
|
4402
|
+
"",
|
|
4403
|
+
"---",
|
|
4404
|
+
"",
|
|
4405
|
+
"## Rules",
|
|
4406
|
+
"",
|
|
4407
|
+
"- **Discover, don't write requirements.** Create issues for the",
|
|
4408
|
+
" requirements-writer \u2014 don't write requirement documents directly.",
|
|
4409
|
+
"- **Deduplicate rigorously.** Check both existing docs and open issues",
|
|
4410
|
+
" before flagging a gap.",
|
|
4411
|
+
"- **Respect decision authority.** Mark ADR/TR proposals as needing human",
|
|
4412
|
+
" decision. Don't create direct-write issues for technology choices.",
|
|
4413
|
+
"- **Bidirectional traceability.** Every `req-scan-*.md` and",
|
|
4414
|
+
" `req-proposals-*.md` must include a `## Produced` section listing the",
|
|
4415
|
+
" downstream requirement issues (and eventual requirement documents) it",
|
|
4416
|
+
" spawned, as markdown links; each formal requirement document under",
|
|
4417
|
+
" `<REQUIREMENTS_ROOT>/` must include a forward link back to the scan or",
|
|
4418
|
+
" proposal that produced it."
|
|
4419
|
+
].join("\n")
|
|
4420
|
+
};
|
|
4421
|
+
var scanRequirementsSkill = {
|
|
4422
|
+
name: "scan-requirements",
|
|
4423
|
+
description: "Kick off a requirements-analyst scan across BCM model docs, competitive analysis, product docs, or meeting extracts. Creates a req:scan issue and dispatches Phase 1.",
|
|
4424
|
+
disableModelInvocation: true,
|
|
4425
|
+
userInvocable: true,
|
|
4426
|
+
context: "fork",
|
|
4427
|
+
agent: "requirements-analyst",
|
|
4428
|
+
platforms: { cursor: { exclude: true } },
|
|
4429
|
+
instructions: [
|
|
4430
|
+
"# Scan Requirements",
|
|
4431
|
+
"",
|
|
4432
|
+
"Kick off a requirements-analyst scan cycle. Creates a `req:scan` issue",
|
|
4433
|
+
"targeted at the requested scope and dispatches Phase 1 (Scan) in the",
|
|
4434
|
+
"requirements-analyst agent.",
|
|
4435
|
+
"",
|
|
4436
|
+
"## Usage",
|
|
4437
|
+
"",
|
|
4438
|
+
"/scan-requirements <scope>",
|
|
4439
|
+
"",
|
|
4440
|
+
"Where `<scope>` is one of:",
|
|
4441
|
+
"- `bcm:<PREFIX-NNN>` \u2014 a single BCM model doc",
|
|
4442
|
+
"- `competitive:<slug>` \u2014 a single competitive analysis doc",
|
|
4443
|
+
"- `product-roadmap` \u2014 the prioritized feature roadmap",
|
|
4444
|
+
"- `entity-taxonomy` \u2014 the entity taxonomy doc",
|
|
4445
|
+
"- `meeting:<slug>` \u2014 a meeting extract",
|
|
4446
|
+
"- `all-bcm` / `all-competitive` \u2014 full sweep (long-running)",
|
|
4447
|
+
"",
|
|
4448
|
+
"## Steps",
|
|
4449
|
+
"",
|
|
4450
|
+
"1. Create a `req:scan` issue with `type:requirement`, `priority:medium`,",
|
|
4451
|
+
" and `status:ready`. Body must list the files to read and the scan scope.",
|
|
4452
|
+
"2. Execute Phase 1 (Scan) of the requirements-analyst agent.",
|
|
4453
|
+
"3. If gaps are found, a `req:draft` issue is created automatically.",
|
|
4454
|
+
"",
|
|
4455
|
+
"## Output",
|
|
4456
|
+
"",
|
|
4457
|
+
"- A `req-scan-<scope>-<YYYY-MM-DD>.md` file under the project's research",
|
|
4458
|
+
" requirements directory.",
|
|
4459
|
+
"- A `req:draft` issue if any gaps were identified."
|
|
4460
|
+
].join("\n")
|
|
4461
|
+
};
|
|
4462
|
+
var requirementsAnalystBundle = {
|
|
4463
|
+
name: "requirements-analyst",
|
|
4464
|
+
description: "Requirements gap-discovery agent bundle for BCM-driven projects. 3-phase pipeline (scan, draft, trace) with req:* phase labels.",
|
|
4465
|
+
appliesWhen: () => true,
|
|
4466
|
+
rules: [
|
|
3363
4467
|
{
|
|
3364
|
-
name: "
|
|
3365
|
-
description: "
|
|
3366
|
-
scope: AGENT_RULE_SCOPE.
|
|
3367
|
-
filePatterns: [
|
|
3368
|
-
"projenrc/**/*.ts",
|
|
3369
|
-
".projenrc.ts",
|
|
3370
|
-
".claude/rules/*.md",
|
|
3371
|
-
".cursor/rules/*.mdc",
|
|
3372
|
-
"CLAUDE.md"
|
|
3373
|
-
],
|
|
4468
|
+
name: "requirements-analyst-workflow",
|
|
4469
|
+
description: "Describes the 3-phase requirements gap-discovery pipeline, the req:* label taxonomy, and the boundary with the downstream requirements-writer agent.",
|
|
4470
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
3374
4471
|
content: [
|
|
3375
|
-
"#
|
|
3376
|
-
"",
|
|
3377
|
-
"Agent rules for Claude and Cursor are **generated** by configulator's `AgentConfig` component. The generated output files (`.claude/rules/`, `.cursor/rules/`, `CLAUDE.md`) must not be edited directly \u2014 they are overwritten on every `npx projen` run.",
|
|
3378
|
-
"",
|
|
3379
|
-
"## Adding Repo-Specific Rules",
|
|
3380
|
-
"",
|
|
3381
|
-
"Rules that only apply to this repository should be added to the `agentConfig.rules` array in the Projen project definition (`.projenrc.ts` or `projenrc/*.ts`):",
|
|
3382
|
-
"",
|
|
3383
|
-
"```typescript",
|
|
3384
|
-
"agentConfig: {",
|
|
3385
|
-
" rules: [",
|
|
3386
|
-
" {",
|
|
3387
|
-
" name: 'my-repo-rule',",
|
|
3388
|
-
" description: 'What this rule does',",
|
|
3389
|
-
" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN with filePatterns",
|
|
3390
|
-
" content: '# My Rule\\n\\n- Guideline 1\\n- Guideline 2',",
|
|
3391
|
-
" },",
|
|
3392
|
-
" ],",
|
|
3393
|
-
"}",
|
|
3394
|
-
"```",
|
|
3395
|
-
"",
|
|
3396
|
-
"## Extending Existing Bundle Rules",
|
|
3397
|
-
"",
|
|
3398
|
-
"To append repo-specific content to a rule provided by a configulator bundle (without replacing it), use `agentConfig.ruleExtensions`:",
|
|
4472
|
+
"# Requirements Analyst Workflow",
|
|
3399
4473
|
"",
|
|
3400
|
-
"
|
|
3401
|
-
"
|
|
3402
|
-
"
|
|
3403
|
-
"
|
|
3404
|
-
" },",
|
|
3405
|
-
"}",
|
|
3406
|
-
"```",
|
|
4474
|
+
"Use `/scan-requirements <scope>` to kick off a requirements gap",
|
|
4475
|
+
"discovery cycle. The pipeline runs in 3 phases \u2014 scan, draft, trace \u2014",
|
|
4476
|
+
"each tracked by its own GitHub issue labeled `req:scan`, `req:draft`,",
|
|
4477
|
+
"or `req:trace`. All issues carry `type:requirement`.",
|
|
3407
4478
|
"",
|
|
3408
|
-
"
|
|
4479
|
+
"The requirements-analyst *discovers gaps and drafts proposals*; it",
|
|
4480
|
+
"does **not** write final requirement documents. Writing is the job of",
|
|
4481
|
+
"the downstream requirements-writer (BCM writer) agent. Keep that",
|
|
4482
|
+
"boundary clean: proposals land under the research requirements",
|
|
4483
|
+
"directory, not under the authoritative requirements tree.",
|
|
3409
4484
|
"",
|
|
3410
|
-
"
|
|
4485
|
+
"See the `requirements-analyst` agent definition for full workflow",
|
|
4486
|
+
"details and phase-by-phase instructions."
|
|
3411
4487
|
].join("\n"),
|
|
4488
|
+
platforms: {
|
|
4489
|
+
cursor: { exclude: true }
|
|
4490
|
+
},
|
|
3412
4491
|
tags: ["workflow"]
|
|
4492
|
+
}
|
|
4493
|
+
],
|
|
4494
|
+
skills: [scanRequirementsSkill],
|
|
4495
|
+
subAgents: [requirementsAnalystSubAgent],
|
|
4496
|
+
labels: [
|
|
4497
|
+
{
|
|
4498
|
+
name: "type:requirement",
|
|
4499
|
+
color: "1D76DB",
|
|
4500
|
+
description: "Work that produces or discovers a requirement document (FR, BR, NFR, etc.)"
|
|
3413
4501
|
},
|
|
3414
4502
|
{
|
|
3415
|
-
name: "
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
"- After making Projen changes, run `npx projen` to synthesize",
|
|
3429
|
-
"",
|
|
3430
|
-
"## Workspace Dependencies",
|
|
3431
|
-
"",
|
|
3432
|
-
"When adding dependencies between packages in a monorepo:",
|
|
3433
|
-
"",
|
|
3434
|
-
'- Use the workspace protocol: `project.addDeps("@org/sibling-pkg@workspace:*")`',
|
|
3435
|
-
"- This ensures the local version is always resolved, not a registry version",
|
|
3436
|
-
'- For dev dependencies: `project.addDevDeps("@org/sibling-pkg@workspace:*")`',
|
|
3437
|
-
"",
|
|
3438
|
-
"## The `configureMyProject` Pattern",
|
|
3439
|
-
"",
|
|
3440
|
-
"Each package should expose a `configureMyProject(options)` factory function that creates and configures its Projen project:",
|
|
3441
|
-
"",
|
|
3442
|
-
"```typescript",
|
|
3443
|
-
"export function configureMyProject(",
|
|
3444
|
-
" options: MyProjectOptions,",
|
|
3445
|
-
"): TypeScriptProject {",
|
|
3446
|
-
" const project = new TypeScriptProject({",
|
|
3447
|
-
" ...options,",
|
|
3448
|
-
" // package-specific defaults",
|
|
3449
|
-
" });",
|
|
3450
|
-
"",
|
|
3451
|
-
" // Attach components, configure rules, etc.",
|
|
3452
|
-
" return project;",
|
|
3453
|
-
"}",
|
|
3454
|
-
"```",
|
|
3455
|
-
"",
|
|
3456
|
-
"This pattern keeps `.projenrc.ts` clean and makes package configuration reusable and testable.",
|
|
3457
|
-
"",
|
|
3458
|
-
"## Custom Projen Components",
|
|
3459
|
-
"",
|
|
3460
|
-
"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:",
|
|
3461
|
-
"",
|
|
3462
|
-
"```typescript",
|
|
3463
|
-
"export class MyComponent extends Component {",
|
|
3464
|
-
" public static of(project: Project): MyComponent | undefined {",
|
|
3465
|
-
" const isDefined = (c: Component): c is MyComponent =>",
|
|
3466
|
-
" c instanceof MyComponent;",
|
|
3467
|
-
" return project.components.find(isDefined);",
|
|
3468
|
-
" }",
|
|
3469
|
-
"",
|
|
3470
|
-
" constructor(project: Project, options: MyComponentOptions) {",
|
|
3471
|
-
" super(project);",
|
|
3472
|
-
" // Implementation",
|
|
3473
|
-
" }",
|
|
3474
|
-
"}",
|
|
3475
|
-
"```",
|
|
3476
|
-
"",
|
|
3477
|
-
"## Component Authoring",
|
|
3478
|
-
"",
|
|
3479
|
-
"- Export project types and utilities from `index.ts`",
|
|
3480
|
-
"- Follow Projen's component lifecycle patterns",
|
|
3481
|
-
"- Use `merge` from `ts-deepmerge` for deep merging configuration objects",
|
|
3482
|
-
"- Components should be reusable and configurable; use TypeScript interfaces for component options",
|
|
3483
|
-
"- Provide sensible defaults while allowing customization",
|
|
3484
|
-
"- Document public APIs with minimal JSDoc; put extended documentation in markdown",
|
|
3485
|
-
"",
|
|
3486
|
-
"## Dependencies",
|
|
3487
|
-
"",
|
|
3488
|
-
"- Dependencies managed through Projen configuration, not directly in `package.json`",
|
|
3489
|
-
'- Use catalog dependencies when available (e.g., `"projen": "catalog:"`)',
|
|
3490
|
-
"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)",
|
|
3491
|
-
'- Use workspace protocol for internal packages: `"@org/pkg@workspace:*"`'
|
|
3492
|
-
].join("\n"),
|
|
3493
|
-
tags: ["workflow"]
|
|
4503
|
+
name: "req:scan",
|
|
4504
|
+
color: "C5DEF5",
|
|
4505
|
+
description: "Phase 1: scan source docs for requirement gaps and deduplicate"
|
|
4506
|
+
},
|
|
4507
|
+
{
|
|
4508
|
+
name: "req:draft",
|
|
4509
|
+
color: "BFDADC",
|
|
4510
|
+
description: "Phase 2: draft requirement proposals for the requirements-writer"
|
|
4511
|
+
},
|
|
4512
|
+
{
|
|
4513
|
+
name: "req:trace",
|
|
4514
|
+
color: "D4C5F9",
|
|
4515
|
+
description: "Phase 3: create requirement issues and backfill traceability on source docs"
|
|
3494
4516
|
}
|
|
3495
4517
|
]
|
|
3496
4518
|
};
|
|
3497
4519
|
|
|
3498
|
-
// src/agent/bundles/
|
|
3499
|
-
var
|
|
3500
|
-
name: "
|
|
3501
|
-
description: "
|
|
4520
|
+
// src/agent/bundles/research-pipeline.ts
|
|
4521
|
+
var researchAnalystSubAgent = {
|
|
4522
|
+
name: "research-analyst",
|
|
4523
|
+
description: "Runs a generic research micro-task pipeline (scope, slice search/synthesize, verify). One phase per session, tracked by research:* GitHub issue labels with filesystem-based durability between phases.",
|
|
3502
4524
|
model: AGENT_MODEL.POWERFUL,
|
|
3503
4525
|
maxTurns: 80,
|
|
3504
4526
|
platforms: { cursor: { exclude: true } },
|
|
3505
4527
|
prompt: [
|
|
3506
|
-
"#
|
|
4528
|
+
"# Research Analyst Agent",
|
|
3507
4529
|
"",
|
|
3508
|
-
"
|
|
3509
|
-
"
|
|
3510
|
-
"
|
|
3511
|
-
"
|
|
3512
|
-
"
|
|
4530
|
+
"Generic research micro-task pipeline. Given a research question, you",
|
|
4531
|
+
"break it into a scope, a fixed number of focused search/synthesize",
|
|
4532
|
+
"slices, and a verification pass that reconciles the slice outputs into",
|
|
4533
|
+
"a single deliverable. Each phase runs as its **own agent session**,",
|
|
4534
|
+
"triggered by a GitHub issue with a `research:*` phase label. You",
|
|
4535
|
+
"handle exactly **one phase per session** \u2014 read the issue to determine",
|
|
4536
|
+
"which phase to execute.",
|
|
4537
|
+
"",
|
|
4538
|
+
"This agent is **domain-neutral**. It makes no assumptions about what",
|
|
4539
|
+
"is being researched (companies, products, people, markets, technical",
|
|
4540
|
+
"topics, academic literature, etc.). All domain-specific vocabulary,",
|
|
4541
|
+
"output locations, and acceptance criteria come from the invoking",
|
|
4542
|
+
"issue body or the consuming project's configuration.",
|
|
3513
4543
|
"",
|
|
3514
4544
|
"Follow your project's shared agent conventions (`AGENTS.md`,",
|
|
3515
4545
|
"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.",
|
|
3516
4546
|
"",
|
|
3517
4547
|
"---",
|
|
3518
4548
|
"",
|
|
3519
|
-
...
|
|
4549
|
+
...PROJECT_CONTEXT_READER_SECTION,
|
|
3520
4550
|
"## Design Principles",
|
|
3521
4551
|
"",
|
|
3522
|
-
"1. **
|
|
3523
|
-
"
|
|
3524
|
-
"
|
|
3525
|
-
"
|
|
3526
|
-
"
|
|
3527
|
-
"
|
|
3528
|
-
"
|
|
3529
|
-
"
|
|
3530
|
-
"
|
|
3531
|
-
"
|
|
3532
|
-
"
|
|
4552
|
+
"1. **Micro-tasks, not mega-prompts.** Split work into small slices so",
|
|
4553
|
+
" each session has a bounded context window and a single deliverable.",
|
|
4554
|
+
"2. **Filesystem durability.** Every phase persists its output to a",
|
|
4555
|
+
" file on disk before closing its issue. Downstream phases read those",
|
|
4556
|
+
" files \u2014 never rely on session memory.",
|
|
4557
|
+
"3. **Issue graph = state machine.** Phase ordering is encoded with",
|
|
4558
|
+
" `Depends on: #N` links between phase issues. A phase runs only",
|
|
4559
|
+
" after its predecessor is closed.",
|
|
4560
|
+
"4. **Generic over specific.** No hardcoded domains, companies, source",
|
|
4561
|
+
" projects, or proprietary taxonomies. Use placeholders that the",
|
|
4562
|
+
" skill invocation or consuming project fills in.",
|
|
4563
|
+
"5. **Verifiable synthesis.** The verify phase re-reads every slice",
|
|
4564
|
+
" output and produces a single deliverable whose claims can each be",
|
|
4565
|
+
" traced back to a slice.",
|
|
3533
4566
|
"",
|
|
3534
4567
|
"---",
|
|
3535
4568
|
"",
|
|
3536
4569
|
"## State Machine Overview",
|
|
3537
4570
|
"",
|
|
3538
|
-
"Requirements synthesis flows through **3 phases**:",
|
|
3539
|
-
"",
|
|
3540
4571
|
"```",
|
|
3541
|
-
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
3542
|
-
"\u2502 1.
|
|
3543
|
-
"\u2502
|
|
3544
|
-
"\u2502
|
|
3545
|
-
"\u2502
|
|
3546
|
-
"\u2502
|
|
3547
|
-
"\u2502
|
|
3548
|
-
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
4572
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
4573
|
+
"\u2502 1. SCOPE \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 2. SLICE (\xD7N) \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 3. VERIFY \u2502",
|
|
4574
|
+
"\u2502 Turn the \u2502 \u2502 For each slice: \u2502 \u2502 Read every \u2502",
|
|
4575
|
+
"\u2502 question \u2502 \u2502 search sources, \u2502 \u2502 slice \u2502",
|
|
4576
|
+
"\u2502 into N \u2502 \u2502 synthesize a \u2502 \u2502 output, \u2502",
|
|
4577
|
+
"\u2502 focused \u2502 \u2502 bounded note file \u2502 \u2502 reconcile, \u2502",
|
|
4578
|
+
"\u2502 slices \u2502 \u2502 \u2502 \u2502 deliverable \u2502",
|
|
4579
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
3549
4580
|
"```",
|
|
3550
4581
|
"",
|
|
3551
4582
|
"**Issue labels encode the phase:**",
|
|
3552
4583
|
"",
|
|
3553
4584
|
"| Label | Phase | Session work |",
|
|
3554
4585
|
"|-------|-------|-------------|",
|
|
3555
|
-
"| `
|
|
3556
|
-
"| `
|
|
3557
|
-
"| `
|
|
4586
|
+
"| `research:scope` | 1. Scope | Decompose the research question into N focused slices. Write a scope file. Create N `research:slice` issues. |",
|
|
4587
|
+
"| `research:slice` | 2. Slice | Execute one slice: search authorized sources, synthesize, write a single slice note file. |",
|
|
4588
|
+
"| `research:verify` | 3. Verify | Read every slice note, reconcile findings, produce the final deliverable and a verification report. |",
|
|
3558
4589
|
"",
|
|
3559
|
-
"All issues also carry `type:
|
|
4590
|
+
"All issues also carry `type:research` and a `status:*` label.",
|
|
3560
4591
|
"",
|
|
3561
|
-
"**Issue count per
|
|
4592
|
+
"**Issue count per research cycle:** 1 scope + N slice + 1 verify =",
|
|
4593
|
+
"**N + 2 sessions**. Typical N is 3\u20136.",
|
|
3562
4594
|
"",
|
|
3563
4595
|
"**Shortened paths:**",
|
|
3564
|
-
"-
|
|
3565
|
-
"
|
|
3566
|
-
"
|
|
4596
|
+
"- Scope phase determines the question is unanswerable or out of scope",
|
|
4597
|
+
" \u2192 scope issue closes with a justification and no downstream issues",
|
|
4598
|
+
" are created \u2192 **1 session**.",
|
|
4599
|
+
"- Single-slice research (N = 1) \u2192 **3 sessions**. Never skip verify,",
|
|
4600
|
+
" even with one slice \u2014 verify is where the deliverable lands.",
|
|
3567
4601
|
"",
|
|
3568
4602
|
"---",
|
|
3569
4603
|
"",
|
|
3570
4604
|
"## Configurable Paths",
|
|
3571
4605
|
"",
|
|
3572
|
-
"
|
|
3573
|
-
"
|
|
4606
|
+
"The pipeline uses these placeholders. Consuming projects override the",
|
|
4607
|
+
"defaults by passing paths in the `/research` skill invocation or by",
|
|
4608
|
+
"extending this rule in their own `agentConfig.rules`.",
|
|
3574
4609
|
"",
|
|
3575
|
-
"| Placeholder | Meaning |
|
|
3576
|
-
"
|
|
3577
|
-
"| `<
|
|
3578
|
-
"| `<
|
|
3579
|
-
"| `<
|
|
3580
|
-
"| `<
|
|
3581
|
-
"| `<
|
|
3582
|
-
"| `<
|
|
3583
|
-
"| `<PREFIX>` | Project-specific requirement ID prefix | e.g. `VRTX`, `ACME` |",
|
|
4610
|
+
"| Placeholder | Meaning | Default |",
|
|
4611
|
+
"|-------------|---------|---------|",
|
|
4612
|
+
"| `<RESEARCH_ROOT>` | Root folder for all research outputs | `docs/research/` |",
|
|
4613
|
+
"| `<SCOPE_DIR>` | Scope files | `<RESEARCH_ROOT>/scopes/` |",
|
|
4614
|
+
"| `<SLICES_DIR>` | Slice note files | `<RESEARCH_ROOT>/slices/` |",
|
|
4615
|
+
"| `<DELIVERABLES_DIR>` | Final verified deliverables | `<RESEARCH_ROOT>/deliverables/` |",
|
|
4616
|
+
"| `<RESEARCH_SLUG>` | Short kebab-case slug identifying one research cycle | derived from the question |",
|
|
4617
|
+
"| `<N>` | Number of slices (default 4, max 8) | `4` |",
|
|
3584
4618
|
"",
|
|
3585
|
-
"If
|
|
3586
|
-
"
|
|
4619
|
+
"If `docs/project-context.md` specifies a different research tree,",
|
|
4620
|
+
"prefer that. Otherwise fall back to the defaults above.",
|
|
3587
4621
|
"",
|
|
3588
4622
|
"---",
|
|
3589
4623
|
"",
|
|
@@ -3591,348 +4625,340 @@ var requirementsAnalystSubAgent = {
|
|
|
3591
4625
|
"",
|
|
3592
4626
|
"Run this loop exactly once per session. Never start a second issue.",
|
|
3593
4627
|
"",
|
|
3594
|
-
"1. Claim one open `type:
|
|
3595
|
-
" `
|
|
3596
|
-
"2. Transition `status:ready` \u2192 `status:in-progress` and create the
|
|
3597
|
-
" per your project's branch-naming convention.",
|
|
3598
|
-
"3. Execute the phase handler that matches the issue's `
|
|
3599
|
-
"
|
|
3600
|
-
"
|
|
4628
|
+
"1. Claim one open `type:research` issue using phase priority:",
|
|
4629
|
+
" `research:scope` > `research:slice` > `research:verify`.",
|
|
4630
|
+
"2. Transition `status:ready` \u2192 `status:in-progress` and create the",
|
|
4631
|
+
" branch per your project's branch-naming convention.",
|
|
4632
|
+
"3. Execute the phase handler that matches the issue's `research:*`",
|
|
4633
|
+
" label.",
|
|
4634
|
+
"4. Commit, push, open a PR (if applicable), and close the issue per",
|
|
4635
|
+
" your project's PR workflow.",
|
|
3601
4636
|
"",
|
|
3602
4637
|
"---",
|
|
3603
4638
|
"",
|
|
3604
|
-
"## Phase 1:
|
|
3605
|
-
"",
|
|
3606
|
-
"**Goal:** Read source documents, identify where requirements are missing,",
|
|
3607
|
-
"incomplete, or contradictory, then check each potential gap against existing",
|
|
3608
|
-
"requirements and open issues to eliminate duplicates. Produces a single",
|
|
3609
|
-
"deduplicated scan report.",
|
|
3610
|
-
"",
|
|
3611
|
-
"**Budget:** Reading source docs + reading requirement registries + searching",
|
|
3612
|
-
"issues. Write one deduplicated scan output file.",
|
|
3613
|
-
"",
|
|
3614
|
-
"### Scan Sources",
|
|
4639
|
+
"## Phase 1: Scope (`research:scope`)",
|
|
3615
4640
|
"",
|
|
3616
|
-
"
|
|
4641
|
+
"**Goal:** Turn a natural-language research question into a bounded",
|
|
4642
|
+
"scope file and `N` focused slice issues.",
|
|
3617
4643
|
"",
|
|
3618
|
-
"
|
|
3619
|
-
"
|
|
3620
|
-
"
|
|
3621
|
-
"| **Competitive analysis** | One `comp-*.md` doc under `<COMPETITIVE_ROOT>` | Feature comparison gaps \u2014 competitor features the product lacks requirements for |",
|
|
3622
|
-
"| **Product roadmap** | `<PRODUCT_ROOT>/prioritized-feature-roadmap.md` | Roadmap items without corresponding FRs |",
|
|
3623
|
-
"| **Entity taxonomy** | `<PRODUCT_ROOT>/entity-taxonomy.md` | Entities without CRUD requirements (FR), data requirements (DR), or security requirements (SEC) |",
|
|
3624
|
-
"| **Meeting extract** | `<MEETINGS_ROOT>/meeting-*.extract.md` | Requirements identified but not yet formalized |",
|
|
4644
|
+
"**Budget:** No web searches in this phase. Read the question, the",
|
|
4645
|
+
"project context, and any cited source material already on disk. Write",
|
|
4646
|
+
"one scope file. Create N slice issues.",
|
|
3625
4647
|
"",
|
|
3626
4648
|
"### Steps",
|
|
3627
4649
|
"",
|
|
3628
|
-
"1. **Read the
|
|
3629
|
-
"",
|
|
3630
|
-
"
|
|
3631
|
-
" -
|
|
3632
|
-
"
|
|
3633
|
-
" -
|
|
3634
|
-
" -
|
|
3635
|
-
"
|
|
3636
|
-
"",
|
|
3637
|
-
"3. **Read the requirements registry.** Scan `_index.md` files in each",
|
|
3638
|
-
" `<REQUIREMENTS_ROOT>/<category>/` directory to know what already exists.",
|
|
4650
|
+
"1. **Read the research question** from the issue body. The body should",
|
|
4651
|
+
" include:",
|
|
4652
|
+
" - The question itself",
|
|
4653
|
+
" - Authorized source categories (e.g. public web, vendor docs, a",
|
|
4654
|
+
" cited local file path) \u2014 if absent, default to public web only",
|
|
4655
|
+
" - Output acceptance criteria for the final deliverable",
|
|
4656
|
+
" - Optional: `<N>` override, `<RESEARCH_SLUG>` override, custom",
|
|
4657
|
+
" output paths",
|
|
3639
4658
|
"",
|
|
3640
|
-
"
|
|
3641
|
-
"
|
|
3642
|
-
|
|
3643
|
-
" --json number,title --limit 100",
|
|
3644
|
-
" ```",
|
|
4659
|
+
"2. **Derive `<RESEARCH_SLUG>`** if not supplied \u2014 a 3\u20135 word kebab-case",
|
|
4660
|
+
" summary of the question. Ensure the slug is not already in use",
|
|
4661
|
+
" under `<SCOPE_DIR>/`.",
|
|
3645
4662
|
"",
|
|
3646
|
-
"
|
|
3647
|
-
" -
|
|
3648
|
-
" -
|
|
3649
|
-
" -
|
|
3650
|
-
" -
|
|
4663
|
+
"3. **Decompose the question into N slices.** Each slice must:",
|
|
4664
|
+
" - Be answerable independently of the others",
|
|
4665
|
+
" - Fit inside a single agent session's context budget",
|
|
4666
|
+
" - Have a clearly scoped set of sources to consult",
|
|
4667
|
+
" - Produce a bounded note file (target: under 1500 words)",
|
|
3651
4668
|
"",
|
|
3652
|
-
"
|
|
3653
|
-
"
|
|
3654
|
-
" <RESEARCH_REQUIREMENTS_ROOT>/req-scan-<scope>-<YYYY-MM-DD>.md",
|
|
3655
|
-
" ```",
|
|
4669
|
+
"4. **Write the scope file** to",
|
|
4670
|
+
" `<SCOPE_DIR>/<RESEARCH_SLUG>.scope.md`:",
|
|
3656
4671
|
"",
|
|
3657
|
-
" Format:",
|
|
3658
4672
|
" ```markdown",
|
|
3659
4673
|
" ---",
|
|
3660
|
-
' title: "
|
|
4674
|
+
' title: "Research Scope: <question>"',
|
|
4675
|
+
" slug: <RESEARCH_SLUG>",
|
|
3661
4676
|
" date: YYYY-MM-DD",
|
|
3662
4677
|
" parent_issue: <N>",
|
|
3663
|
-
"
|
|
4678
|
+
" slice_count: <N>",
|
|
3664
4679
|
" ---",
|
|
3665
4680
|
"",
|
|
3666
|
-
" #
|
|
4681
|
+
" # Research Scope: <question>",
|
|
3667
4682
|
"",
|
|
3668
|
-
" ##
|
|
3669
|
-
"
|
|
4683
|
+
" ## Question",
|
|
4684
|
+
" <verbatim question from the issue>",
|
|
3670
4685
|
"",
|
|
3671
|
-
" ##
|
|
3672
|
-
" - <category
|
|
4686
|
+
" ## Authorized Sources",
|
|
4687
|
+
" - <source category or path>",
|
|
3673
4688
|
"",
|
|
3674
|
-
" ##
|
|
3675
|
-
"
|
|
3676
|
-
" - **Category:** FR / BR / NFR / SEC / DR / INT / OPS / UX / MT / ADR / TR",
|
|
3677
|
-
" - **Source:** <path to doc + section that revealed this gap>",
|
|
3678
|
-
" - **Priority:** High / Normal / Low",
|
|
3679
|
-
" - **Rationale:** <why this requirement is needed>",
|
|
3680
|
-
" - **Duplicate check:** No existing requirement or open issue found",
|
|
3681
|
-
" - **Proposed scope:** <1-2 sentences on what the requirement should cover>",
|
|
4689
|
+
" ## Acceptance Criteria",
|
|
4690
|
+
" - [ ] <criterion for the final deliverable>",
|
|
3682
4691
|
"",
|
|
3683
|
-
" ##
|
|
3684
|
-
"
|
|
4692
|
+
" ## Slices",
|
|
4693
|
+
" ### Slice 1: <title>",
|
|
4694
|
+
" - **Focus:** <what this slice answers>",
|
|
4695
|
+
" - **Sources:** <the subset of authorized sources this slice uses>",
|
|
4696
|
+
" - **Output:** <SLICES_DIR>/<RESEARCH_SLUG>-01-<slug>.slice.md",
|
|
3685
4697
|
"",
|
|
3686
|
-
"
|
|
3687
|
-
"
|
|
4698
|
+
" ### Slice 2: <title>",
|
|
4699
|
+
" ...",
|
|
3688
4700
|
"",
|
|
3689
|
-
" ##
|
|
3690
|
-
" <
|
|
4701
|
+
" ## Out of Scope",
|
|
4702
|
+
" <sub-questions deliberately excluded from this cycle>",
|
|
4703
|
+
"",
|
|
4704
|
+
" ## Deliverable",
|
|
4705
|
+
" <DELIVERABLES_DIR>/<RESEARCH_SLUG>.md",
|
|
3691
4706
|
" ```",
|
|
3692
4707
|
"",
|
|
3693
|
-
"
|
|
3694
|
-
"
|
|
3695
|
-
"
|
|
3696
|
-
" - If **no gaps** were found \u2192 stop (no further phases needed). Comment",
|
|
3697
|
-
" on the issue noting that no gaps were identified, and proceed directly",
|
|
3698
|
-
" to commit and push. The scan issue will be marked done with no",
|
|
3699
|
-
" downstream work needed.",
|
|
4708
|
+
"5. **Create N `research:slice` issues**, one per slice, each with",
|
|
4709
|
+
" `Depends on: #<scope-issue>`. Each slice issue body references the",
|
|
4710
|
+
" scope file and names the exact slice (by number and title).",
|
|
3700
4711
|
"",
|
|
3701
|
-
"
|
|
4712
|
+
"6. **Create one `research:verify` issue** that depends on all N slice",
|
|
4713
|
+
" issues. Its body references the scope file and lists every slice",
|
|
4714
|
+
" output path that verify must read.",
|
|
4715
|
+
"",
|
|
4716
|
+
"7. **Commit and push** the scope file. Close the scope issue.",
|
|
3702
4717
|
"",
|
|
3703
4718
|
"---",
|
|
3704
4719
|
"",
|
|
3705
|
-
"## Phase 2:
|
|
4720
|
+
"## Phase 2: Slice (`research:slice`)",
|
|
3706
4721
|
"",
|
|
3707
|
-
"**Goal:**
|
|
3708
|
-
"
|
|
4722
|
+
"**Goal:** Answer one slice by searching the authorized sources and",
|
|
4723
|
+
"writing a single slice note file.",
|
|
3709
4724
|
"",
|
|
3710
|
-
"**Budget:**
|
|
4725
|
+
"**Budget:** Search budget is one slice \u2014 do not expand scope. Write",
|
|
4726
|
+
"one slice note. Do not create downstream issues.",
|
|
3711
4727
|
"",
|
|
3712
4728
|
"### Steps",
|
|
3713
4729
|
"",
|
|
3714
|
-
"1. **Read the
|
|
4730
|
+
"1. **Read the scope file** referenced in the issue body.",
|
|
3715
4731
|
"",
|
|
3716
|
-
"2. **
|
|
4732
|
+
"2. **Identify your slice** by number and title. Re-read the slice's",
|
|
4733
|
+
" focus, sources, and output path.",
|
|
3717
4734
|
"",
|
|
3718
|
-
"
|
|
3719
|
-
"
|
|
4735
|
+
"3. **Search the authorized sources.** Stay within the source list for",
|
|
4736
|
+
" your slice \u2014 do not broaden to the full scope's source list unless",
|
|
4737
|
+
" the slice explicitly permits it.",
|
|
3720
4738
|
"",
|
|
3721
|
-
"
|
|
3722
|
-
"
|
|
3723
|
-
" **Source:** <document path and section>",
|
|
4739
|
+
"4. **Synthesize a slice note** and write it to the slice's output",
|
|
4740
|
+
" path (e.g. `<SLICES_DIR>/<RESEARCH_SLUG>-NN-<slug>.slice.md`):",
|
|
3724
4741
|
"",
|
|
3725
|
-
"
|
|
3726
|
-
"
|
|
4742
|
+
" ```markdown",
|
|
4743
|
+
" ---",
|
|
4744
|
+
' title: "Slice NN: <title>"',
|
|
4745
|
+
" slug: <RESEARCH_SLUG>",
|
|
4746
|
+
" slice: NN",
|
|
4747
|
+
" date: YYYY-MM-DD",
|
|
4748
|
+
" parent_scope: <SCOPE_DIR>/<RESEARCH_SLUG>.scope.md",
|
|
4749
|
+
" parent_issue: <N>",
|
|
4750
|
+
" ---",
|
|
3727
4751
|
"",
|
|
3728
|
-
"
|
|
3729
|
-
" - [ ] <testable criterion 1>",
|
|
3730
|
-
" - [ ] <testable criterion 2>",
|
|
3731
|
-
" - [ ] <testable criterion 3>",
|
|
4752
|
+
" # Slice NN: <title>",
|
|
3732
4753
|
"",
|
|
3733
|
-
"
|
|
3734
|
-
"
|
|
3735
|
-
" - **Related:** <existing requirements that interact with this one>",
|
|
3736
|
-
" - **Source:** <BCM doc, competitive analysis, or meeting that revealed",
|
|
3737
|
-
" the gap \u2014 use a markdown link. If the source is a meeting note, the",
|
|
3738
|
-
" downstream requirement doc must include the same meeting as a link in",
|
|
3739
|
-
" its Traceability `Related:` list.>",
|
|
4754
|
+
" ## Question",
|
|
4755
|
+
" <the slice-level question>",
|
|
3740
4756
|
"",
|
|
3741
|
-
"
|
|
3742
|
-
|
|
3743
|
-
' decision" for ADR/TR, or "Mixed \u2014 defer technology choices" for',
|
|
3744
|
-
" DR/MT/INT/OPS>",
|
|
4757
|
+
" ## Key Findings",
|
|
4758
|
+
" - <finding> \u2014 source: <citation>",
|
|
3745
4759
|
"",
|
|
3746
|
-
"
|
|
3747
|
-
" <
|
|
3748
|
-
" coverage, relevant competitive features>",
|
|
3749
|
-
" ```",
|
|
4760
|
+
" ## Evidence",
|
|
4761
|
+
" <short quotations, paraphrases, or structured data with citations>",
|
|
3750
4762
|
"",
|
|
3751
|
-
"
|
|
3752
|
-
"
|
|
3753
|
-
" <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<YYYY-MM-DD>.md",
|
|
3754
|
-
" ```",
|
|
4763
|
+
" ## Gaps / Open Questions",
|
|
4764
|
+
" <anything the slice could not answer inside its budget>",
|
|
3755
4765
|
"",
|
|
3756
|
-
"
|
|
3757
|
-
"
|
|
3758
|
-
"
|
|
4766
|
+
" ## Sources",
|
|
4767
|
+
" - <source URL or file path> \u2014 <date accessed>",
|
|
4768
|
+
" ```",
|
|
3759
4769
|
"",
|
|
3760
|
-
"5. **
|
|
4770
|
+
"5. **Stay within the word budget** (default 1500 words). If the slice",
|
|
4771
|
+
" cannot fit, add an `## Overflow` section at the end noting what was",
|
|
4772
|
+
" cut and flag it for the verify phase \u2014 do not expand into other",
|
|
4773
|
+
" slices' territory.",
|
|
3761
4774
|
"",
|
|
3762
|
-
"6. **Commit and push
|
|
4775
|
+
"6. **Commit and push** the slice note. Close the slice issue.",
|
|
3763
4776
|
"",
|
|
3764
4777
|
"---",
|
|
3765
4778
|
"",
|
|
3766
|
-
"## Phase 3:
|
|
4779
|
+
"## Phase 3: Verify (`research:verify`)",
|
|
3767
4780
|
"",
|
|
3768
|
-
"**Goal:**
|
|
3769
|
-
"source documents with traceability notes indicating that requirement issues",
|
|
3770
|
-
"were created.",
|
|
4781
|
+
"**Goal:** Reconcile every slice into a single verified deliverable.",
|
|
3771
4782
|
"",
|
|
3772
|
-
"**Budget:** No web searches.
|
|
3773
|
-
"
|
|
4783
|
+
"**Budget:** No new web searches. Read the scope, read every slice",
|
|
4784
|
+
"note, reconcile contradictions, write the deliverable and a short",
|
|
4785
|
+
"verification report.",
|
|
3774
4786
|
"",
|
|
3775
4787
|
"### Steps",
|
|
3776
4788
|
"",
|
|
3777
|
-
"1. **Read the
|
|
4789
|
+
"1. **Read the scope file** and every slice note listed in the issue",
|
|
4790
|
+
" body. If any slice file is missing, stop and re-open the",
|
|
4791
|
+
" corresponding slice issue with `status:needs-attention`.",
|
|
3778
4792
|
"",
|
|
3779
|
-
"2. **
|
|
4793
|
+
"2. **Build a claim index.** For every assertion in any slice, note",
|
|
4794
|
+
" which slice(s) support it and which sources back it.",
|
|
3780
4795
|
"",
|
|
3781
|
-
"
|
|
3782
|
-
"
|
|
4796
|
+
"3. **Reconcile contradictions.** When slices disagree:",
|
|
4797
|
+
" - Prefer the slice with stronger sources",
|
|
4798
|
+
" - Flag unresolved contradictions in the verification report",
|
|
4799
|
+
" - Do not silently pick a side",
|
|
3783
4800
|
"",
|
|
3784
|
-
"
|
|
3785
|
-
"
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
' --body "## Objective',
|
|
3789
|
-
" Write <PREFIX>-<NNN> \u2014 <title>.",
|
|
4801
|
+
"4. **Write the deliverable** to",
|
|
4802
|
+
" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.md`. The structure is dictated",
|
|
4803
|
+
" by the acceptance criteria in the scope file. Every factual claim",
|
|
4804
|
+
" in the deliverable must cite at least one slice note.",
|
|
3790
4805
|
"",
|
|
3791
|
-
"
|
|
3792
|
-
"
|
|
3793
|
-
" - **Proposals file:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md",
|
|
4806
|
+
"5. **Write a verification report** to",
|
|
4807
|
+
" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.verify.md`:",
|
|
3794
4808
|
"",
|
|
3795
|
-
"
|
|
3796
|
-
"
|
|
3797
|
-
|
|
4809
|
+
" ```markdown",
|
|
4810
|
+
" ---",
|
|
4811
|
+
' title: "Verification Report: <question>"',
|
|
4812
|
+
" slug: <RESEARCH_SLUG>",
|
|
4813
|
+
" date: YYYY-MM-DD",
|
|
4814
|
+
" parent_issue: <N>",
|
|
4815
|
+
" slices_read: <count>",
|
|
4816
|
+
" ---",
|
|
3798
4817
|
"",
|
|
3799
|
-
"
|
|
3800
|
-
" - [ ] Requirement document follows <category> template",
|
|
3801
|
-
" - [ ] Traceability links to source BCM/competitive/product doc",
|
|
3802
|
-
" - [ ] Registry index updated",
|
|
3803
|
-
" - [ ] Decision authority rules followed (direct write vs. proposed)",
|
|
4818
|
+
" # Verification Report: <question>",
|
|
3804
4819
|
"",
|
|
3805
|
-
" ##
|
|
3806
|
-
"
|
|
4820
|
+
" ## Acceptance Criteria Coverage",
|
|
4821
|
+
" - [x] <criterion> \u2014 covered by slice(s) <NN, NN>",
|
|
4822
|
+
" - [ ] <criterion> \u2014 **not covered**; gap noted in deliverable",
|
|
3807
4823
|
"",
|
|
3808
|
-
" ##
|
|
3809
|
-
|
|
3810
|
-
"
|
|
4824
|
+
" ## Slice Coverage",
|
|
4825
|
+
" | Slice | Claims | Reused in deliverable | Notes |",
|
|
4826
|
+
" |-------|--------|-----------------------|-------|",
|
|
4827
|
+
" | 01 | <count> | <count> | |",
|
|
3811
4828
|
"",
|
|
3812
|
-
"
|
|
3813
|
-
"
|
|
3814
|
-
" strategic-implications section (whichever heading the source doc uses)",
|
|
3815
|
-
" indicating that a requirement issue was created:",
|
|
4829
|
+
" ## Reconciled Contradictions",
|
|
4830
|
+
" - <short summary of each reconciled contradiction and why>",
|
|
3816
4831
|
"",
|
|
3817
|
-
"
|
|
3818
|
-
" -
|
|
3819
|
-
"
|
|
4832
|
+
" ## Unresolved Contradictions",
|
|
4833
|
+
" - <contradiction the verifier could not resolve>",
|
|
4834
|
+
"",
|
|
4835
|
+
" ## Gaps",
|
|
4836
|
+
" - <question the pipeline could not answer>",
|
|
3820
4837
|
" ```",
|
|
3821
4838
|
"",
|
|
3822
|
-
"
|
|
3823
|
-
"
|
|
4839
|
+
"6. **Comment on the scope issue** with a summary linking to the",
|
|
4840
|
+
" deliverable and verification report.",
|
|
3824
4841
|
"",
|
|
3825
|
-
"
|
|
4842
|
+
"7. **Commit and push.** Close the verify issue.",
|
|
3826
4843
|
"",
|
|
3827
4844
|
"---",
|
|
3828
4845
|
"",
|
|
3829
|
-
"##
|
|
3830
|
-
"",
|
|
3831
|
-
"| Direction | Agent | What |",
|
|
3832
|
-
"|-----------|-------|------|",
|
|
3833
|
-
"| Upstream | BCM Writer | Scans capability-model docs for project-relevance gaps (judged against `docs/project-context.md`) |",
|
|
3834
|
-
"| Upstream | Company Research | Scans competitive analysis for feature comparison gaps |",
|
|
3835
|
-
"| Upstream | Meeting Analyst | Scans meeting extracts for requirement proposals |",
|
|
3836
|
-
"| Downstream | Requirements Writer (BCM Writer) | Creates `type:requirement` issues for the skill to draft |",
|
|
3837
|
-
"",
|
|
3838
|
-
"**File boundaries:** Writes to `<RESEARCH_REQUIREMENTS_ROOT>/req-*.md` and",
|
|
3839
|
-
"minor traceability edits to `<BCM_DOCS_ROOT>` and `<COMPETITIVE_ROOT>`.",
|
|
3840
|
-
"Never writes to `<REQUIREMENTS_ROOT>/` \u2014 that is owned by the",
|
|
3841
|
-
"requirements-writer agent.",
|
|
4846
|
+
"## Output Boundaries",
|
|
3842
4847
|
"",
|
|
3843
|
-
"
|
|
4848
|
+
"This agent writes **only** to:",
|
|
3844
4849
|
"",
|
|
3845
|
-
"
|
|
4850
|
+
"- `<SCOPE_DIR>/` \u2014 scope files (Phase 1)",
|
|
4851
|
+
"- `<SLICES_DIR>/` \u2014 slice notes (Phase 2)",
|
|
4852
|
+
"- `<DELIVERABLES_DIR>/` \u2014 deliverables and verification reports",
|
|
4853
|
+
" (Phase 3)",
|
|
3846
4854
|
"",
|
|
3847
|
-
"
|
|
3848
|
-
"
|
|
3849
|
-
"
|
|
3850
|
-
"-
|
|
4855
|
+
"The pipeline produces **notes and deliverables only**. It does not",
|
|
4856
|
+
"open downstream `type:requirement`, profile, or comparison issues \u2014",
|
|
4857
|
+
"those are the responsibility of specialized downstream agents (e.g.",
|
|
4858
|
+
"`requirements-analyst`, `meeting-analyst`) that consume the",
|
|
4859
|
+
"deliverables produced here. Keep this boundary clean so the research",
|
|
4860
|
+
"pipeline stays generic.",
|
|
3851
4861
|
"",
|
|
3852
4862
|
"---",
|
|
3853
4863
|
"",
|
|
3854
4864
|
"## Rules",
|
|
3855
4865
|
"",
|
|
3856
|
-
"- **
|
|
3857
|
-
"
|
|
3858
|
-
"- **
|
|
3859
|
-
" before
|
|
3860
|
-
"- **
|
|
3861
|
-
"
|
|
3862
|
-
"
|
|
3863
|
-
"
|
|
3864
|
-
"
|
|
3865
|
-
"
|
|
3866
|
-
"
|
|
3867
|
-
"
|
|
4866
|
+
"- **One phase per session.** Never run two phases back-to-back in a",
|
|
4867
|
+
" single session.",
|
|
4868
|
+
"- **Persist before closing.** Every phase must write its output file",
|
|
4869
|
+
" before closing its issue.",
|
|
4870
|
+
"- **Do not expand scope mid-slice.** Overflow goes into the slice's",
|
|
4871
|
+
" overflow section and is flagged for verify \u2014 not into another",
|
|
4872
|
+
" slice's territory.",
|
|
4873
|
+
"- **Cite everything.** Claims without a source citation do not belong",
|
|
4874
|
+
" in a slice note or deliverable.",
|
|
4875
|
+
"- **Produce notes, not downstream work.** Do not create",
|
|
4876
|
+
" `type:requirement`, profile, or comparison issues from this",
|
|
4877
|
+
" pipeline. Emit deliverables under `<DELIVERABLES_DIR>/` and let",
|
|
4878
|
+
" downstream agents decide what to do with them."
|
|
3868
4879
|
].join("\n")
|
|
3869
4880
|
};
|
|
3870
|
-
var
|
|
3871
|
-
name: "
|
|
3872
|
-
description: "Kick off a
|
|
4881
|
+
var researchSkill = {
|
|
4882
|
+
name: "research",
|
|
4883
|
+
description: "Kick off a generic research micro-task pipeline. Creates a research:scope issue and dispatches Phase 1 (Scope) in the research-analyst agent.",
|
|
3873
4884
|
disableModelInvocation: true,
|
|
3874
4885
|
userInvocable: true,
|
|
3875
4886
|
context: "fork",
|
|
3876
|
-
agent: "
|
|
4887
|
+
agent: "research-analyst",
|
|
3877
4888
|
platforms: { cursor: { exclude: true } },
|
|
3878
4889
|
instructions: [
|
|
3879
|
-
"#
|
|
4890
|
+
"# Research",
|
|
3880
4891
|
"",
|
|
3881
|
-
"Kick off a
|
|
3882
|
-
"
|
|
3883
|
-
"
|
|
4892
|
+
"Kick off a generic research micro-task pipeline. Creates a",
|
|
4893
|
+
"`research:scope` issue carrying the research question and dispatches",
|
|
4894
|
+
"Phase 1 (Scope) in the research-analyst agent.",
|
|
3884
4895
|
"",
|
|
3885
4896
|
"## Usage",
|
|
3886
4897
|
"",
|
|
3887
|
-
"/
|
|
4898
|
+
"/research <question>",
|
|
3888
4899
|
"",
|
|
3889
|
-
"
|
|
3890
|
-
"- `
|
|
3891
|
-
"- `
|
|
3892
|
-
"- `
|
|
3893
|
-
"- `
|
|
3894
|
-
"
|
|
3895
|
-
"
|
|
4900
|
+
"Optional extensions in the question body:",
|
|
4901
|
+
"- `sources: <list>` \u2014 authorized source categories or file paths",
|
|
4902
|
+
"- `slices: <N>` \u2014 override the default slice count (default 4, max 8)",
|
|
4903
|
+
"- `slug: <kebab-case>` \u2014 override the derived research slug",
|
|
4904
|
+
"- `acceptance: <list>` \u2014 explicit acceptance criteria for the",
|
|
4905
|
+
" deliverable",
|
|
4906
|
+
"",
|
|
4907
|
+
"## Default Paths",
|
|
4908
|
+
"",
|
|
4909
|
+
"If the project has no override in `docs/project-context.md` or",
|
|
4910
|
+
"`agentConfig.rules`, outputs land under:",
|
|
4911
|
+
"",
|
|
4912
|
+
"- `docs/research/scopes/<slug>.scope.md`",
|
|
4913
|
+
"- `docs/research/slices/<slug>-NN-<slice-slug>.slice.md`",
|
|
4914
|
+
"- `docs/research/deliverables/<slug>.md`",
|
|
4915
|
+
"- `docs/research/deliverables/<slug>.verify.md`",
|
|
3896
4916
|
"",
|
|
3897
4917
|
"## Steps",
|
|
3898
4918
|
"",
|
|
3899
|
-
"1. Create a `
|
|
3900
|
-
" and `status:ready`. Body must
|
|
3901
|
-
"
|
|
3902
|
-
"
|
|
4919
|
+
"1. Create a `research:scope` issue with `type:research`,",
|
|
4920
|
+
" `priority:medium`, and `status:ready`. Body must include the",
|
|
4921
|
+
" verbatim question, authorized sources, and any overrides.",
|
|
4922
|
+
"2. Execute Phase 1 (Scope) of the research-analyst agent.",
|
|
4923
|
+
"3. Phase 1 creates `research:slice` issues (one per slice) and a",
|
|
4924
|
+
" single `research:verify` issue. Each downstream issue declares",
|
|
4925
|
+
" its `Depends on:` predecessor.",
|
|
3903
4926
|
"",
|
|
3904
4927
|
"## Output",
|
|
3905
4928
|
"",
|
|
3906
|
-
"- A
|
|
3907
|
-
"
|
|
3908
|
-
"- A
|
|
4929
|
+
"- A scope file under the project's research scope directory",
|
|
4930
|
+
"- One slice note per slice under the slices directory",
|
|
4931
|
+
"- A single deliverable plus verification report under the deliverables",
|
|
4932
|
+
" directory",
|
|
4933
|
+
"- This pipeline produces **notes and deliverables only** \u2014 it does",
|
|
4934
|
+
" not open downstream `type:requirement` or profile issues."
|
|
3909
4935
|
].join("\n")
|
|
3910
4936
|
};
|
|
3911
|
-
var
|
|
3912
|
-
name: "
|
|
3913
|
-
description: "
|
|
3914
|
-
appliesWhen: () =>
|
|
4937
|
+
var researchPipelineBundle = {
|
|
4938
|
+
name: "research-pipeline",
|
|
4939
|
+
description: "Generic research micro-task pipeline: scope, N-way slice search/synthesize, and verify. Opt-in only; domain-neutral; filesystem-durable between phases.",
|
|
4940
|
+
appliesWhen: () => false,
|
|
3915
4941
|
rules: [
|
|
3916
4942
|
{
|
|
3917
|
-
name: "
|
|
3918
|
-
description: "Describes the 3-phase
|
|
4943
|
+
name: "research-pipeline-workflow",
|
|
4944
|
+
description: "Describes the 3-phase generic research pipeline, the research:* label taxonomy, and the boundary against downstream specialized agents.",
|
|
3919
4945
|
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
3920
4946
|
content: [
|
|
3921
|
-
"#
|
|
4947
|
+
"# Research Pipeline Workflow",
|
|
3922
4948
|
"",
|
|
3923
|
-
"Use `/
|
|
3924
|
-
"
|
|
3925
|
-
"each tracked by its own GitHub issue labeled
|
|
3926
|
-
"
|
|
4949
|
+
"Use `/research <question>` to kick off a generic research",
|
|
4950
|
+
"micro-task pipeline. The pipeline runs in 3 phases \u2014 scope, slice,",
|
|
4951
|
+
"verify \u2014 each tracked by its own GitHub issue labeled",
|
|
4952
|
+
"`research:scope`, `research:slice`, or `research:verify`. All",
|
|
4953
|
+
"issues carry `type:research`.",
|
|
3927
4954
|
"",
|
|
3928
|
-
"The
|
|
3929
|
-
"
|
|
3930
|
-
"
|
|
3931
|
-
"
|
|
3932
|
-
"directory, not under the authoritative requirements tree.",
|
|
4955
|
+
"The pipeline produces **notes and deliverables only**. It does",
|
|
4956
|
+
"not open downstream `type:requirement` or profile issues \u2014 those",
|
|
4957
|
+
"belong to specialized downstream agents that consume the",
|
|
4958
|
+
"deliverables.",
|
|
3933
4959
|
"",
|
|
3934
|
-
"See the `
|
|
3935
|
-
"details and phase-by-phase instructions."
|
|
4960
|
+
"See the `research-analyst` agent definition for full workflow",
|
|
4961
|
+
"details, default paths, and phase-by-phase instructions."
|
|
3936
4962
|
].join("\n"),
|
|
3937
4963
|
platforms: {
|
|
3938
4964
|
cursor: { exclude: true }
|
|
@@ -3940,55 +4966,94 @@ var requirementsAnalystBundle = {
|
|
|
3940
4966
|
tags: ["workflow"]
|
|
3941
4967
|
}
|
|
3942
4968
|
],
|
|
3943
|
-
skills: [
|
|
3944
|
-
subAgents: [
|
|
4969
|
+
skills: [researchSkill],
|
|
4970
|
+
subAgents: [researchAnalystSubAgent],
|
|
3945
4971
|
labels: [
|
|
3946
4972
|
{
|
|
3947
|
-
name: "type:
|
|
3948
|
-
color: "
|
|
3949
|
-
description: "Work that produces or
|
|
4973
|
+
name: "type:research",
|
|
4974
|
+
color: "5319E7",
|
|
4975
|
+
description: "Work that produces or consumes a research note, slice, or deliverable"
|
|
3950
4976
|
},
|
|
3951
4977
|
{
|
|
3952
|
-
name: "
|
|
4978
|
+
name: "research:scope",
|
|
3953
4979
|
color: "C5DEF5",
|
|
3954
|
-
description: "Phase 1:
|
|
4980
|
+
description: "Phase 1: decompose a research question into N focused slice issues"
|
|
3955
4981
|
},
|
|
3956
4982
|
{
|
|
3957
|
-
name: "
|
|
4983
|
+
name: "research:slice",
|
|
3958
4984
|
color: "BFDADC",
|
|
3959
|
-
description: "Phase 2:
|
|
4985
|
+
description: "Phase 2: execute one research slice \u2014 search authorized sources and write a slice note"
|
|
3960
4986
|
},
|
|
3961
4987
|
{
|
|
3962
|
-
name: "
|
|
4988
|
+
name: "research:verify",
|
|
3963
4989
|
color: "D4C5F9",
|
|
3964
|
-
description: "Phase 3:
|
|
4990
|
+
description: "Phase 3: reconcile slice notes into a verified deliverable"
|
|
3965
4991
|
}
|
|
3966
4992
|
]
|
|
3967
4993
|
};
|
|
3968
4994
|
|
|
3969
|
-
// src/agent/bundles/
|
|
3970
|
-
var
|
|
3971
|
-
name: "
|
|
3972
|
-
description: "
|
|
4995
|
+
// src/agent/bundles/slack.ts
|
|
4996
|
+
var slackBundle = {
|
|
4997
|
+
name: "slack",
|
|
4998
|
+
description: "Slack MCP message formatting and best practices",
|
|
4999
|
+
appliesWhen: () => false,
|
|
5000
|
+
rules: [
|
|
5001
|
+
{
|
|
5002
|
+
name: "slack-message-formatting",
|
|
5003
|
+
description: "Format Slack messages with explicit links so bullets and labels render correctly",
|
|
5004
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
5005
|
+
content: [
|
|
5006
|
+
"# Slack Message Formatting",
|
|
5007
|
+
"",
|
|
5008
|
+
"When composing or sending messages to Slack (e.g., via Slack MCP tools like `slack_send_message`), use formatting that Slack's mrkdwn parser renders correctly.",
|
|
5009
|
+
"",
|
|
5010
|
+
"## Rules",
|
|
5011
|
+
"",
|
|
5012
|
+
"1. **Use Slack's explicit link syntax** for any link in a message:",
|
|
5013
|
+
" - Format: `<https://example.com|display text>`",
|
|
5014
|
+
" - Text outside the angle brackets (bullets, labels) stays separate and won't merge into the link",
|
|
5015
|
+
"",
|
|
5016
|
+
"2. **Do not rely on auto-linkification** when the message has bullets or labels before URLs \u2014 auto-linked URLs can break or merge with surrounding text",
|
|
5017
|
+
"",
|
|
5018
|
+
"3. **Put each list item on its own line** with a newline between items so list structure is clear",
|
|
5019
|
+
"",
|
|
5020
|
+
"4. **Example \u2014 preferred:**",
|
|
5021
|
+
" ```",
|
|
5022
|
+
" Status update:",
|
|
5023
|
+
"",
|
|
5024
|
+
" \u2022 Feature A: <https://github.com/org/repo/pull/1|repo#1>",
|
|
5025
|
+
" \u2022 Feature B: <https://github.com/org/repo/pull/2|repo#2>",
|
|
5026
|
+
" ```",
|
|
5027
|
+
"",
|
|
5028
|
+
"5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `\u2022 Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links"
|
|
5029
|
+
].join("\n"),
|
|
5030
|
+
tags: ["workflow"]
|
|
5031
|
+
}
|
|
5032
|
+
]
|
|
5033
|
+
};
|
|
5034
|
+
|
|
5035
|
+
// src/agent/bundles/software-profile.ts
|
|
5036
|
+
var softwareProfileAnalystSubAgent = {
|
|
5037
|
+
name: "software-profile-analyst",
|
|
5038
|
+
description: "Researches a software product (competitor, adjacent, incumbent, enabler, infrastructure, or ecosystem-tool) from public sources, produces a structured markdown profile, and contributes rows to a shared feature matrix ranked against configurable segment-importance weights. One product per session, tracked by software:* GitHub issue labels.",
|
|
3973
5039
|
model: AGENT_MODEL.POWERFUL,
|
|
3974
5040
|
maxTurns: 80,
|
|
3975
5041
|
platforms: { cursor: { exclude: true } },
|
|
3976
5042
|
prompt: [
|
|
3977
|
-
"#
|
|
5043
|
+
"# Software Profile Analyst Agent",
|
|
3978
5044
|
"",
|
|
3979
|
-
"
|
|
3980
|
-
"
|
|
3981
|
-
"
|
|
3982
|
-
"
|
|
3983
|
-
"
|
|
3984
|
-
"handle exactly **one phase per session** \u2014 read the issue to determine",
|
|
3985
|
-
"which phase to execute.",
|
|
5045
|
+
"You research a single software product from public sources and write",
|
|
5046
|
+
"a structured markdown profile. Each profile cycle runs across a small",
|
|
5047
|
+
"sequence of GitHub issues \u2014 one per phase \u2014 and produces a single",
|
|
5048
|
+
"profile file on disk, a set of feature-matrix rows, and optional",
|
|
5049
|
+
"follow-up research issues for adjacent products.",
|
|
3986
5050
|
"",
|
|
3987
5051
|
"This agent is **domain-neutral**. It makes no assumptions about what",
|
|
3988
|
-
"
|
|
3989
|
-
"
|
|
3990
|
-
"output locations, and
|
|
3991
|
-
"issue body or the consuming
|
|
5052
|
+
"the consuming project sells, which industry it serves, or which",
|
|
5053
|
+
"products matter to it. All domain-specific vocabulary, segment",
|
|
5054
|
+
"weights, feature taxonomies, output locations, and profile-template",
|
|
5055
|
+
"overrides come from the invoking issue body or the consuming",
|
|
5056
|
+
"project's configuration.",
|
|
3992
5057
|
"",
|
|
3993
5058
|
"Follow your project's shared agent conventions (`AGENTS.md`,",
|
|
3994
5059
|
"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.",
|
|
@@ -3998,75 +5063,144 @@ var researchAnalystSubAgent = {
|
|
|
3998
5063
|
...PROJECT_CONTEXT_READER_SECTION,
|
|
3999
5064
|
"## Design Principles",
|
|
4000
5065
|
"",
|
|
4001
|
-
"1. **
|
|
4002
|
-
"
|
|
4003
|
-
"2. **
|
|
4004
|
-
"
|
|
4005
|
-
"
|
|
4006
|
-
"
|
|
4007
|
-
"
|
|
4008
|
-
"
|
|
4009
|
-
"
|
|
4010
|
-
"
|
|
4011
|
-
"
|
|
4012
|
-
"
|
|
4013
|
-
"
|
|
4014
|
-
"
|
|
5066
|
+
"1. **One product per session.** Never profile two products in a",
|
|
5067
|
+
" single session, even if they came up together.",
|
|
5068
|
+
"2. **Public sources only.** Use the product's own site, docs, pricing",
|
|
5069
|
+
" pages, changelogs, public demos, and similar public material. Do",
|
|
5070
|
+
" not attempt to access gated or paywalled content unless the",
|
|
5071
|
+
" invoking issue body explicitly authorizes it.",
|
|
5072
|
+
"3. **Filesystem durability.** The profile file and feature-matrix",
|
|
5073
|
+
" rows are the deliverables. Both are committed to disk before the",
|
|
5074
|
+
" profile issue closes. Downstream phases read from disk \u2014 never",
|
|
5075
|
+
" rely on session memory.",
|
|
5076
|
+
"4. **Generic over specific.** No hardcoded product types, feature",
|
|
5077
|
+
" taxonomies, or segment assumptions. Use the generic software-type",
|
|
5078
|
+
" taxonomy below and let consuming projects override it via their",
|
|
5079
|
+
" `docs/project-context.md` or `agentConfig.rules`.",
|
|
5080
|
+
"5. **Cite everything.** Every non-trivial factual claim in the",
|
|
5081
|
+
" profile must carry a source citation (URL plus access date).",
|
|
5082
|
+
"6. **Follow-up, don't widen scope.** If the session turns up adjacent",
|
|
5083
|
+
" products worth evaluating, emit a follow-up issue rather than",
|
|
5084
|
+
" expanding the profile beyond its scope.",
|
|
5085
|
+
"7. **Segment weights live in project context.** Segment-importance",
|
|
5086
|
+
" weights belong in `docs/project-context.md` (or an override",
|
|
5087
|
+
" passed in the issue body). This agent reads them; it never",
|
|
5088
|
+
" invents them.",
|
|
5089
|
+
"",
|
|
5090
|
+
"---",
|
|
5091
|
+
"",
|
|
5092
|
+
"## Software Type Taxonomy",
|
|
5093
|
+
"",
|
|
5094
|
+
"Pick exactly one type per software profile. The taxonomy is",
|
|
5095
|
+
"deliberately generic \u2014 consuming projects override it via",
|
|
5096
|
+
"`agentConfig.rules` if they need a domain-specific refinement.",
|
|
5097
|
+
"",
|
|
5098
|
+
"| Type | Use for |",
|
|
5099
|
+
"|------|---------|",
|
|
5100
|
+
"| `competitor` | Products that offer a substitutable feature set to the same buyers for the same jobs-to-be-done. |",
|
|
5101
|
+
"| `adjacent` | Products that solve a neighboring problem or serve an overlapping buyer \u2014 not a direct substitute but worth understanding for positioning and integration. |",
|
|
5102
|
+
"| `incumbent` | Established, widely-deployed products that define the status quo in the space. Often older, broader, and harder to displace. |",
|
|
5103
|
+
"| `enabler` | Products the consuming project might build on, integrate with, or resell. Platforms, SDKs, APIs, and similar building blocks. |",
|
|
5104
|
+
"| `infrastructure` | Lower-level infrastructure or runtime components the consuming project depends on (databases, queues, identity, observability, etc.). |",
|
|
5105
|
+
"| `ecosystem-tool` | Developer tooling, plugins, extensions, or companion products that surround an incumbent or competitor without being one themselves. |",
|
|
5106
|
+
"",
|
|
5107
|
+
"If the product plausibly fits two types, prefer the one that reflects",
|
|
5108
|
+
"the **reason the profile was requested**, and note the secondary",
|
|
5109
|
+
"type in the profile body.",
|
|
5110
|
+
"",
|
|
5111
|
+
"---",
|
|
5112
|
+
"",
|
|
5113
|
+
"## Segment-Importance Weights",
|
|
5114
|
+
"",
|
|
5115
|
+
"Feature ranking uses **segment-importance weights** \u2014 a small table",
|
|
5116
|
+
"that assigns a numeric weight to each customer segment the consuming",
|
|
5117
|
+
"project cares about. Higher weight means the segment matters more to",
|
|
5118
|
+
"the project's own strategy; features that serve high-weight segments",
|
|
5119
|
+
"rank higher in the matrix.",
|
|
5120
|
+
"",
|
|
5121
|
+
"**Convention:** segment weights live in `docs/project-context.md`",
|
|
5122
|
+
"under a `## Segment Weights` section. The format is a simple",
|
|
5123
|
+
"markdown table with `segment` and `weight` columns. Weights are",
|
|
5124
|
+
"non-negative numbers; the scale is project-defined (0\u20131, 0\u201310, and",
|
|
5125
|
+
"0\u2013100 are all valid as long as the project is internally",
|
|
5126
|
+
"consistent).",
|
|
5127
|
+
"",
|
|
5128
|
+
"Example `docs/project-context.md` fragment:",
|
|
5129
|
+
"",
|
|
5130
|
+
"```markdown",
|
|
5131
|
+
"## Segment Weights",
|
|
5132
|
+
"",
|
|
5133
|
+
"| segment | weight |",
|
|
5134
|
+
"|---------|--------|",
|
|
5135
|
+
"| enterprise | 3 |",
|
|
5136
|
+
"| mid-market | 2 |",
|
|
5137
|
+
"| smb | 1 |",
|
|
5138
|
+
"| hobbyist | 0.5 |",
|
|
5139
|
+
"```",
|
|
5140
|
+
"",
|
|
5141
|
+
"If `docs/project-context.md` does not define segment weights,",
|
|
5142
|
+
"**do not invent them**. Either:",
|
|
5143
|
+
"",
|
|
5144
|
+
"- Accept an `weights:` override in the invoking issue body, or",
|
|
5145
|
+
"- Produce the feature matrix with a single segment (`default`)",
|
|
5146
|
+
" weighted `1` and flag the missing weights in the profile's",
|
|
5147
|
+
" `## Open Questions` section.",
|
|
4015
5148
|
"",
|
|
4016
5149
|
"---",
|
|
4017
5150
|
"",
|
|
4018
5151
|
"## State Machine Overview",
|
|
4019
5152
|
"",
|
|
4020
5153
|
"```",
|
|
4021
|
-
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
4022
|
-
"\u2502
|
|
4023
|
-
"\u2502
|
|
4024
|
-
"\u2502
|
|
4025
|
-
"\u2502
|
|
4026
|
-
"\u2502
|
|
4027
|
-
"\u2502
|
|
4028
|
-
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
5154
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
5155
|
+
"\u2502 1. RESEARCH \u2502\u2500\u2500\u25B6\u2502 2. PROFILE \u2502\u2500\u2500\u25B6\u2502 3. MATRIX \u2502\u2500\u2500\u25B6\u2502 4. FOLLOWUP \u2502",
|
|
5156
|
+
"\u2502 Collect \u2502 \u2502 Write the \u2502 \u2502 Extract \u2502 \u2502 Enqueue \u2502",
|
|
5157
|
+
"\u2502 public \u2502 \u2502 structured \u2502 \u2502 feature rows \u2502 \u2502 research for \u2502",
|
|
5158
|
+
"\u2502 sources into \u2502 \u2502 markdown \u2502 \u2502 and score \u2502 \u2502 adjacent \u2502",
|
|
5159
|
+
"\u2502 bounded \u2502 \u2502 profile to \u2502 \u2502 against the \u2502 \u2502 products \u2502",
|
|
5160
|
+
"\u2502 notes file \u2502 \u2502 <PROFILES>/ \u2502 \u2502 weights \u2502 \u2502 surfaced \u2502",
|
|
5161
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
4029
5162
|
"```",
|
|
4030
5163
|
"",
|
|
4031
5164
|
"**Issue labels encode the phase:**",
|
|
4032
5165
|
"",
|
|
4033
5166
|
"| Label | Phase | Session work |",
|
|
4034
5167
|
"|-------|-------|-------------|",
|
|
4035
|
-
"| `research
|
|
4036
|
-
"| `
|
|
4037
|
-
"| `
|
|
5168
|
+
"| `software:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the profile issue. |",
|
|
5169
|
+
"| `software:profile` | 2. Profile | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the matrix issue. |",
|
|
5170
|
+
"| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the follow-up issue if warranted. |",
|
|
5171
|
+
"| `software:followup` | 4. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |",
|
|
4038
5172
|
"",
|
|
4039
|
-
"All issues also carry `type:
|
|
5173
|
+
"All issues also carry `type:software-profile` and a `status:*` label.",
|
|
4040
5174
|
"",
|
|
4041
|
-
"**Issue count per
|
|
4042
|
-
"
|
|
5175
|
+
"**Issue count per product cycle:** 1 research + 1 profile + 1 matrix +",
|
|
5176
|
+
"0\u20131 followup = **3\u20134 sessions**. The followup phase is skipped when",
|
|
5177
|
+
"the profile did not surface any adjacent product worth researching.",
|
|
4043
5178
|
"",
|
|
4044
5179
|
"**Shortened paths:**",
|
|
4045
|
-
"-
|
|
4046
|
-
" \u2192
|
|
4047
|
-
" are created \u2192 **1 session**.",
|
|
4048
|
-
"-
|
|
4049
|
-
" even with one slice \u2014 verify is where the deliverable lands.",
|
|
5180
|
+
"- Research phase determines the product is out of scope (not",
|
|
5181
|
+
" relevant, insufficient public material) \u2192 research issue closes",
|
|
5182
|
+
" with a justification and no downstream issues are created \u2192 **1 session**.",
|
|
5183
|
+
"- Narrow product with no adjacent candidates \u2192 **3 sessions**.",
|
|
4050
5184
|
"",
|
|
4051
5185
|
"---",
|
|
4052
5186
|
"",
|
|
4053
5187
|
"## Configurable Paths",
|
|
4054
5188
|
"",
|
|
4055
5189
|
"The pipeline uses these placeholders. Consuming projects override the",
|
|
4056
|
-
"defaults by passing paths in the `/
|
|
4057
|
-
"extending this rule in their own `agentConfig.rules`.",
|
|
5190
|
+
"defaults by passing paths in the `/profile-software` skill invocation",
|
|
5191
|
+
"or by extending this rule in their own `agentConfig.rules`.",
|
|
4058
5192
|
"",
|
|
4059
5193
|
"| Placeholder | Meaning | Default |",
|
|
4060
5194
|
"|-------------|---------|---------|",
|
|
4061
|
-
"| `<
|
|
4062
|
-
"| `<
|
|
4063
|
-
"| `<
|
|
4064
|
-
"| `<
|
|
4065
|
-
"| `<
|
|
4066
|
-
"| `<N>` | Number of slices (default 4, max 8) | `4` |",
|
|
5195
|
+
"| `<SOFTWARE_ROOT>` | Root folder for software profiles | `docs/software/` |",
|
|
5196
|
+
"| `<PROFILES_DIR>` | Final software profile files | `<SOFTWARE_ROOT>/profiles/` |",
|
|
5197
|
+
"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<SOFTWARE_ROOT>/notes/` |",
|
|
5198
|
+
"| `<MATRIX_FILE>` | Shared feature-matrix file | `<SOFTWARE_ROOT>/feature-matrix.md` |",
|
|
5199
|
+
"| `<PRODUCT_SLUG>` | Short kebab-case slug identifying the product | derived from the product name |",
|
|
4067
5200
|
"",
|
|
4068
|
-
"If `docs/project-context.md` specifies a different research
|
|
4069
|
-
"
|
|
5201
|
+
"If `docs/project-context.md` specifies a different software-research",
|
|
5202
|
+
"tree (for example by reusing the research-pipeline deliverables",
|
|
5203
|
+
"folder), prefer that. Otherwise fall back to the defaults above.",
|
|
4070
5204
|
"",
|
|
4071
5205
|
"---",
|
|
4072
5206
|
"",
|
|
@@ -4074,221 +5208,275 @@ var researchAnalystSubAgent = {
|
|
|
4074
5208
|
"",
|
|
4075
5209
|
"Run this loop exactly once per session. Never start a second issue.",
|
|
4076
5210
|
"",
|
|
4077
|
-
"1. Claim one open `type:
|
|
4078
|
-
" `research
|
|
5211
|
+
"1. Claim one open `type:software-profile` issue using phase priority:",
|
|
5212
|
+
" `software:research` > `software:profile` > `software:matrix` >",
|
|
5213
|
+
" `software:followup`.",
|
|
4079
5214
|
"2. Transition `status:ready` \u2192 `status:in-progress` and create the",
|
|
4080
5215
|
" branch per your project's branch-naming convention.",
|
|
4081
|
-
"3. Execute the phase handler that matches the issue's `
|
|
5216
|
+
"3. Execute the phase handler that matches the issue's `software:*`",
|
|
4082
5217
|
" label.",
|
|
4083
5218
|
"4. Commit, push, open a PR (if applicable), and close the issue per",
|
|
4084
5219
|
" your project's PR workflow.",
|
|
4085
5220
|
"",
|
|
4086
5221
|
"---",
|
|
4087
5222
|
"",
|
|
4088
|
-
"## Phase 1:
|
|
5223
|
+
"## Phase 1: Research (`software:research`)",
|
|
4089
5224
|
"",
|
|
4090
|
-
"**Goal:**
|
|
4091
|
-
"scope file and `N` focused slice issues.",
|
|
5225
|
+
"**Goal:** Gather public sources into a bounded research-notes file.",
|
|
4092
5226
|
"",
|
|
4093
|
-
"**Budget:**
|
|
4094
|
-
"
|
|
4095
|
-
"
|
|
5227
|
+
"**Budget:** Public web search only, unless the issue body authorizes",
|
|
5228
|
+
"additional sources. Write one notes file. Do not write the profile",
|
|
5229
|
+
"or extend the feature matrix in this phase.",
|
|
4096
5230
|
"",
|
|
4097
5231
|
"### Steps",
|
|
4098
5232
|
"",
|
|
4099
|
-
"1. **Read the
|
|
4100
|
-
"
|
|
4101
|
-
" - The
|
|
4102
|
-
" -
|
|
4103
|
-
"
|
|
4104
|
-
" -
|
|
4105
|
-
"
|
|
4106
|
-
" output paths",
|
|
5233
|
+
"1. **Read the issue body.** It should include:",
|
|
5234
|
+
" - The product name and website (if known)",
|
|
5235
|
+
" - The requested software type from the taxonomy above",
|
|
5236
|
+
" - The reason the profile was requested (framing \u2014 what does the",
|
|
5237
|
+
" invoking project want to learn?)",
|
|
5238
|
+
" - Optional: `<PRODUCT_SLUG>` override, custom output paths,",
|
|
5239
|
+
" `weights:` override for segment-importance weights",
|
|
4107
5240
|
"",
|
|
4108
|
-
"2. **Derive `<
|
|
4109
|
-
" summary of the
|
|
4110
|
-
" under `<
|
|
5241
|
+
"2. **Derive `<PRODUCT_SLUG>`** if not supplied \u2014 a 2\u20134 word",
|
|
5242
|
+
" kebab-case summary of the product name. Ensure the slug is not",
|
|
5243
|
+
" already in use under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.",
|
|
4111
5244
|
"",
|
|
4112
|
-
"3. **
|
|
4113
|
-
" -
|
|
4114
|
-
"
|
|
4115
|
-
" -
|
|
4116
|
-
" -
|
|
5245
|
+
"3. **Gather sources.** Prioritize in this order:",
|
|
5246
|
+
" - The product's own website (home, product, pricing, docs,",
|
|
5247
|
+
" changelog, integrations)",
|
|
5248
|
+
" - Public documentation, developer references, API docs",
|
|
5249
|
+
" - Public changelogs, release notes, roadmap posts",
|
|
5250
|
+
" - Reputable independent reviews and comparison articles",
|
|
5251
|
+
" - Public issue trackers or community forums when the issue body",
|
|
5252
|
+
" authorizes them",
|
|
4117
5253
|
"",
|
|
4118
|
-
"4. **Write
|
|
4119
|
-
" `<
|
|
5254
|
+
"4. **Write a research-notes file** to",
|
|
5255
|
+
" `<NOTES_DIR>/<PRODUCT_SLUG>.notes.md`:",
|
|
4120
5256
|
"",
|
|
4121
5257
|
" ```markdown",
|
|
4122
5258
|
" ---",
|
|
4123
|
-
' title: "Research
|
|
4124
|
-
" slug: <
|
|
5259
|
+
' title: "Research Notes: <product name>"',
|
|
5260
|
+
" slug: <PRODUCT_SLUG>",
|
|
5261
|
+
" software_type: <one of the taxonomy values>",
|
|
4125
5262
|
" date: YYYY-MM-DD",
|
|
4126
5263
|
" parent_issue: <N>",
|
|
4127
|
-
" slice_count: <N>",
|
|
4128
5264
|
" ---",
|
|
4129
5265
|
"",
|
|
4130
|
-
" # Research
|
|
4131
|
-
"",
|
|
4132
|
-
" ## Question",
|
|
4133
|
-
" <verbatim question from the issue>",
|
|
5266
|
+
" # Research Notes: <product name>",
|
|
4134
5267
|
"",
|
|
4135
|
-
" ##
|
|
4136
|
-
"
|
|
5268
|
+
" ## Framing",
|
|
5269
|
+
" <why this product was requested and what to learn>",
|
|
4137
5270
|
"",
|
|
4138
|
-
" ##
|
|
4139
|
-
" -
|
|
5271
|
+
" ## Raw Findings",
|
|
5272
|
+
" - <finding> \u2014 source: <citation>",
|
|
4140
5273
|
"",
|
|
4141
|
-
" ##
|
|
4142
|
-
"
|
|
4143
|
-
" - **Focus:** <what this slice answers>",
|
|
4144
|
-
" - **Sources:** <the subset of authorized sources this slice uses>",
|
|
4145
|
-
" - **Output:** <SLICES_DIR>/<RESEARCH_SLUG>-01-<slug>.slice.md",
|
|
5274
|
+
" ## Candidate Features",
|
|
5275
|
+
" - <feature name>: <one-line description> \u2014 source: <citation>",
|
|
4146
5276
|
"",
|
|
4147
|
-
"
|
|
4148
|
-
"
|
|
5277
|
+
" ## Candidate Adjacent Products",
|
|
5278
|
+
" - <product name> \u2014 source: <citation>",
|
|
4149
5279
|
"",
|
|
4150
|
-
" ##
|
|
4151
|
-
" <
|
|
5280
|
+
" ## Open Questions",
|
|
5281
|
+
" <anything the notes could not answer from public sources>",
|
|
4152
5282
|
"",
|
|
4153
|
-
" ##
|
|
4154
|
-
" <
|
|
5283
|
+
" ## Sources",
|
|
5284
|
+
" - <source URL or file path> \u2014 <date accessed>",
|
|
4155
5285
|
" ```",
|
|
4156
5286
|
"",
|
|
4157
|
-
"5. **Create
|
|
4158
|
-
" `Depends on: #<
|
|
4159
|
-
"
|
|
4160
|
-
"",
|
|
4161
|
-
"6. **Create one `research:verify` issue** that depends on all N slice",
|
|
4162
|
-
" issues. Its body references the scope file and lists every slice",
|
|
4163
|
-
" output path that verify must read.",
|
|
5287
|
+
"5. **Create the `software:profile` issue** with",
|
|
5288
|
+
" `Depends on: #<research-issue>`. Its body references the notes",
|
|
5289
|
+
" file path and the requested software type.",
|
|
4164
5290
|
"",
|
|
4165
|
-
"
|
|
5291
|
+
"6. **Commit and push** the notes file. Close the research issue.",
|
|
4166
5292
|
"",
|
|
4167
5293
|
"---",
|
|
4168
5294
|
"",
|
|
4169
|
-
"## Phase 2:
|
|
5295
|
+
"## Phase 2: Profile (`software:profile`)",
|
|
4170
5296
|
"",
|
|
4171
|
-
"**Goal:**
|
|
4172
|
-
"
|
|
5297
|
+
"**Goal:** Write the structured software profile from the research",
|
|
5298
|
+
"notes.",
|
|
4173
5299
|
"",
|
|
4174
|
-
"**Budget:**
|
|
4175
|
-
"
|
|
5300
|
+
"**Budget:** No new web searches unless explicitly needed to fill a",
|
|
5301
|
+
"gap the notes flagged. Write one profile file.",
|
|
4176
5302
|
"",
|
|
4177
5303
|
"### Steps",
|
|
4178
5304
|
"",
|
|
4179
|
-
"1. **Read the
|
|
4180
|
-
"",
|
|
4181
|
-
"2. **Identify your slice** by number and title. Re-read the slice's",
|
|
4182
|
-
" focus, sources, and output path.",
|
|
4183
|
-
"",
|
|
4184
|
-
"3. **Search the authorized sources.** Stay within the source list for",
|
|
4185
|
-
" your slice \u2014 do not broaden to the full scope's source list unless",
|
|
4186
|
-
" the slice explicitly permits it.",
|
|
5305
|
+
"1. **Read the research-notes file** referenced in the issue body.",
|
|
4187
5306
|
"",
|
|
4188
|
-
"
|
|
4189
|
-
"
|
|
5307
|
+
"2. **Check for duplicates.** If `<PROFILES_DIR>/<PRODUCT_SLUG>.md`",
|
|
5308
|
+
" already exists, open it and decide whether to update in place or",
|
|
5309
|
+
" flag a naming collision. Never silently overwrite a non-trivial",
|
|
5310
|
+
" existing profile.",
|
|
5311
|
+
"",
|
|
5312
|
+
"3. **Write the profile** to `<PROFILES_DIR>/<PRODUCT_SLUG>.md` using",
|
|
5313
|
+
" the template below. All sections are required; use",
|
|
5314
|
+
" `_Not available in public sources._` when a section cannot be",
|
|
5315
|
+
" filled from the notes.",
|
|
4190
5316
|
"",
|
|
4191
5317
|
" ```markdown",
|
|
4192
5318
|
" ---",
|
|
4193
|
-
' title: "
|
|
4194
|
-
" slug: <
|
|
4195
|
-
"
|
|
5319
|
+
' title: "<product name>"',
|
|
5320
|
+
" slug: <PRODUCT_SLUG>",
|
|
5321
|
+
" software_type: <one of the taxonomy values>",
|
|
5322
|
+
" website: <primary URL>",
|
|
4196
5323
|
" date: YYYY-MM-DD",
|
|
4197
|
-
" parent_scope: <SCOPE_DIR>/<RESEARCH_SLUG>.scope.md",
|
|
4198
5324
|
" parent_issue: <N>",
|
|
5325
|
+
" notes: <NOTES_DIR>/<PRODUCT_SLUG>.notes.md",
|
|
4199
5326
|
" ---",
|
|
4200
5327
|
"",
|
|
4201
|
-
" #
|
|
5328
|
+
" # <product name>",
|
|
4202
5329
|
"",
|
|
4203
|
-
" ##
|
|
4204
|
-
" <
|
|
5330
|
+
" ## Summary",
|
|
5331
|
+
" <2\u20134 sentence elevator description: what it does, who it's for>",
|
|
4205
5332
|
"",
|
|
4206
|
-
" ##
|
|
4207
|
-
" -
|
|
5333
|
+
" ## Classification",
|
|
5334
|
+
" - **Primary type:** <taxonomy value>",
|
|
5335
|
+
" - **Secondary type (if any):** <taxonomy value or `n/a`>",
|
|
5336
|
+
" - **Relevance to this project:** <1\u20132 sentences tying the product",
|
|
5337
|
+
" back to the framing from the notes>",
|
|
4208
5338
|
"",
|
|
4209
|
-
" ##
|
|
4210
|
-
"
|
|
5339
|
+
" ## Offering",
|
|
5340
|
+
" - **Jobs-to-be-done:** <bullet list of core use cases>",
|
|
5341
|
+
" - **Target segments:** <who this product is for; reuse segment",
|
|
5342
|
+
" names from the project's segment-weights table when possible>",
|
|
5343
|
+
" - **Pricing model:** <if disclosed>",
|
|
5344
|
+
" - **Deployment model:** <SaaS / self-hosted / hybrid / on-prem>",
|
|
4211
5345
|
"",
|
|
4212
|
-
" ##
|
|
4213
|
-
" <
|
|
5346
|
+
" ## Features",
|
|
5347
|
+
" <grouped bullet list of notable features, each cited. These become",
|
|
5348
|
+
" the rows in the feature matrix during Phase 3.>",
|
|
5349
|
+
"",
|
|
5350
|
+
" ## Technology Signals",
|
|
5351
|
+
" <stack hints from docs, integrations, and public engineering",
|
|
5352
|
+
" content \u2014 each bullet cited>",
|
|
5353
|
+
"",
|
|
5354
|
+
" ## Positioning / Differentiation",
|
|
5355
|
+
" <how the product describes itself and how it differs from adjacent",
|
|
5356
|
+
" products \u2014 use its own language, cited, rather than inferred>",
|
|
5357
|
+
"",
|
|
5358
|
+
" ## Risks / Open Questions",
|
|
5359
|
+
" <what the profile could not answer; flag anything the matrix or",
|
|
5360
|
+
" follow-up phase should escalate>",
|
|
5361
|
+
"",
|
|
5362
|
+
" ## Follow-up Candidates",
|
|
5363
|
+
" - **Adjacent products to evaluate:** <list of candidate product",
|
|
5364
|
+
" names>",
|
|
4214
5365
|
"",
|
|
4215
5366
|
" ## Sources",
|
|
4216
|
-
" - <source URL
|
|
5367
|
+
" - <source URL> \u2014 <date accessed>",
|
|
4217
5368
|
" ```",
|
|
4218
5369
|
"",
|
|
4219
|
-
"
|
|
4220
|
-
"
|
|
4221
|
-
"
|
|
4222
|
-
"
|
|
5370
|
+
"4. **Create the `software:matrix` issue** with",
|
|
5371
|
+
" `Depends on: #<profile-issue>`. Its body references the profile",
|
|
5372
|
+
" path, the matrix file path, and the segment-weights source",
|
|
5373
|
+
" (`docs/project-context.md` or an explicit override).",
|
|
4223
5374
|
"",
|
|
4224
|
-
"
|
|
5375
|
+
"5. **Commit and push** the profile file. Close the profile issue.",
|
|
4225
5376
|
"",
|
|
4226
5377
|
"---",
|
|
4227
5378
|
"",
|
|
4228
|
-
"## Phase 3:
|
|
5379
|
+
"## Phase 3: Matrix (`software:matrix`)",
|
|
4229
5380
|
"",
|
|
4230
|
-
"**Goal:**
|
|
5381
|
+
"**Goal:** Extract feature rows from the profile into the shared",
|
|
5382
|
+
"feature matrix and score each feature against the segment-importance",
|
|
5383
|
+
"weights.",
|
|
4231
5384
|
"",
|
|
4232
|
-
"**Budget:** No new
|
|
4233
|
-
"
|
|
4234
|
-
"
|
|
5385
|
+
"**Budget:** No new research. Read the profile, update the matrix,",
|
|
5386
|
+
"close the phase.",
|
|
5387
|
+
"",
|
|
5388
|
+
"### Matrix File Format",
|
|
5389
|
+
"",
|
|
5390
|
+
"The feature matrix is a single markdown file at `<MATRIX_FILE>`. It",
|
|
5391
|
+
"uses a wide table with one row per (product, feature) pair and one",
|
|
5392
|
+
"column per segment plus a computed `score` column.",
|
|
5393
|
+
"",
|
|
5394
|
+
"```markdown",
|
|
5395
|
+
"---",
|
|
5396
|
+
'title: "Software Feature Matrix"',
|
|
5397
|
+
"weights_source: docs/project-context.md#segment-weights",
|
|
5398
|
+
"updated: YYYY-MM-DD",
|
|
5399
|
+
"---",
|
|
5400
|
+
"",
|
|
5401
|
+
"# Software Feature Matrix",
|
|
5402
|
+
"",
|
|
5403
|
+
"| product | feature | <segment-1> | <segment-2> | ... | score | source |",
|
|
5404
|
+
"|---------|---------|-------------|-------------|-----|-------|--------|",
|
|
5405
|
+
"| <slug> | <feature-name> | 0\u20131 | 0\u20131 | ... | <weighted-sum> | <profile-path> |",
|
|
5406
|
+
"```",
|
|
5407
|
+
"",
|
|
5408
|
+
"Segment columns carry a **coverage score** in `[0, 1]` representing",
|
|
5409
|
+
"how well the feature serves that segment \u2014 `1` means fully covered,",
|
|
5410
|
+
"`0` means not covered, intermediate values reflect partial coverage",
|
|
5411
|
+
"(e.g. self-serve only, gated by pricing tier, limited by scale).",
|
|
5412
|
+
"",
|
|
5413
|
+
"The `score` column is the weighted sum:",
|
|
5414
|
+
"",
|
|
5415
|
+
"```",
|
|
5416
|
+
"score = \u03A3 (coverage[segment] * weight[segment])",
|
|
5417
|
+
"```",
|
|
5418
|
+
"",
|
|
5419
|
+
"using the weights loaded from `docs/project-context.md`.",
|
|
4235
5420
|
"",
|
|
4236
5421
|
"### Steps",
|
|
4237
5422
|
"",
|
|
4238
|
-
"1. **
|
|
4239
|
-
"
|
|
4240
|
-
"
|
|
5423
|
+
"1. **Load segment weights.** Read `## Segment Weights` from",
|
|
5424
|
+
" `docs/project-context.md`. If absent, fall back to the",
|
|
5425
|
+
" `weights:` override in the issue body, or the single-segment",
|
|
5426
|
+
" default described in `## Segment-Importance Weights` above.",
|
|
4241
5427
|
"",
|
|
4242
|
-
"2. **
|
|
4243
|
-
"
|
|
5428
|
+
"2. **Read the profile file** referenced in the issue body. Extract",
|
|
5429
|
+
" the bullets under `## Features` as candidate matrix rows.",
|
|
4244
5430
|
"",
|
|
4245
|
-
"3. **
|
|
4246
|
-
" -
|
|
4247
|
-
"
|
|
4248
|
-
"
|
|
5431
|
+
"3. **Open or create `<MATRIX_FILE>`.** If the file does not exist,",
|
|
5432
|
+
" write the front-matter and header row using the current set of",
|
|
5433
|
+
" segment columns. If it exists, ensure its segment columns match",
|
|
5434
|
+
" the loaded weights; if they have drifted, add any missing columns",
|
|
5435
|
+
" and leave a note in the profile's `## Risks / Open Questions`.",
|
|
4249
5436
|
"",
|
|
4250
|
-
"4. **
|
|
4251
|
-
"
|
|
4252
|
-
"
|
|
4253
|
-
"
|
|
5437
|
+
"4. **Append or update rows** for the current product. One row per",
|
|
5438
|
+
" feature. For each row:",
|
|
5439
|
+
" - Assign a coverage score in `[0, 1]` for each segment, citing",
|
|
5440
|
+
" the profile section that justifies the score.",
|
|
5441
|
+
" - Compute the `score` as the weighted sum.",
|
|
5442
|
+
" - Set the `source` column to the profile file path.",
|
|
4254
5443
|
"",
|
|
4255
|
-
"5. **
|
|
4256
|
-
" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.verify.md`:",
|
|
5444
|
+
"5. **Update the matrix front-matter** (`updated: YYYY-MM-DD`).",
|
|
4257
5445
|
"",
|
|
4258
|
-
"
|
|
4259
|
-
"
|
|
4260
|
-
|
|
4261
|
-
"
|
|
4262
|
-
"
|
|
4263
|
-
" parent_issue: <N>",
|
|
4264
|
-
" slices_read: <count>",
|
|
4265
|
-
" ---",
|
|
5446
|
+
"6. **Decide whether a follow-up issue is warranted.** Create a",
|
|
5447
|
+
" `software:followup` issue (depending on this matrix issue) only",
|
|
5448
|
+
" if the profile lists at least one adjacent product candidate.",
|
|
5449
|
+
" Otherwise, note in the matrix issue's closing comment that no",
|
|
5450
|
+
" follow-up is needed.",
|
|
4266
5451
|
"",
|
|
4267
|
-
"
|
|
5452
|
+
"7. **Commit and push** the matrix file (and any profile updates).",
|
|
5453
|
+
" Close the matrix issue.",
|
|
4268
5454
|
"",
|
|
4269
|
-
"
|
|
4270
|
-
" - [x] <criterion> \u2014 covered by slice(s) <NN, NN>",
|
|
4271
|
-
" - [ ] <criterion> \u2014 **not covered**; gap noted in deliverable",
|
|
5455
|
+
"---",
|
|
4272
5456
|
"",
|
|
4273
|
-
"
|
|
4274
|
-
" | Slice | Claims | Reused in deliverable | Notes |",
|
|
4275
|
-
" |-------|--------|-----------------------|-------|",
|
|
4276
|
-
" | 01 | <count> | <count> | |",
|
|
5457
|
+
"## Phase 4: Followup (`software:followup`)",
|
|
4277
5458
|
"",
|
|
4278
|
-
"
|
|
4279
|
-
"
|
|
5459
|
+
"**Goal:** Create downstream research issues for the adjacent products",
|
|
5460
|
+
"surfaced in the profile.",
|
|
4280
5461
|
"",
|
|
4281
|
-
"
|
|
4282
|
-
"
|
|
5462
|
+
"**Budget:** No new research. Read the profile, enqueue issues, close",
|
|
5463
|
+
"the phase.",
|
|
4283
5464
|
"",
|
|
4284
|
-
"
|
|
4285
|
-
" - <question the pipeline could not answer>",
|
|
4286
|
-
" ```",
|
|
5465
|
+
"### Steps",
|
|
4287
5466
|
"",
|
|
4288
|
-
"
|
|
4289
|
-
" deliverable and verification report.",
|
|
5467
|
+
"1. **Read the profile file** referenced in the issue body.",
|
|
4290
5468
|
"",
|
|
4291
|
-
"
|
|
5469
|
+
"2. **Enqueue software-research issues** for each entry under",
|
|
5470
|
+
" `Follow-up Candidates > Adjacent products to evaluate`. Each new",
|
|
5471
|
+
" issue follows the same 4-phase pipeline \u2014 start it in the",
|
|
5472
|
+
" `software:research` phase with `type:software-profile`,",
|
|
5473
|
+
" `priority:medium`, and `status:ready`.",
|
|
5474
|
+
"",
|
|
5475
|
+
"3. **Cross-link** \u2014 update the profile's `## Follow-up Candidates`",
|
|
5476
|
+
" section so each entry references its newly-created issue number.",
|
|
5477
|
+
"",
|
|
5478
|
+
"4. **Commit and push** (if the profile was updated). Close the",
|
|
5479
|
+
" followup issue.",
|
|
4292
5480
|
"",
|
|
4293
5481
|
"---",
|
|
4294
5482
|
"",
|
|
@@ -4296,118 +5484,133 @@ var researchAnalystSubAgent = {
|
|
|
4296
5484
|
"",
|
|
4297
5485
|
"This agent writes **only** to:",
|
|
4298
5486
|
"",
|
|
4299
|
-
"- `<
|
|
4300
|
-
"- `<
|
|
4301
|
-
"
|
|
4302
|
-
"
|
|
5487
|
+
"- `<NOTES_DIR>/` \u2014 research-notes files (Phase 1)",
|
|
5488
|
+
"- `<PROFILES_DIR>/` \u2014 software profiles (Phase 2, updated in later",
|
|
5489
|
+
" phases)",
|
|
5490
|
+
"- `<MATRIX_FILE>` \u2014 shared feature matrix (Phase 3)",
|
|
4303
5491
|
"",
|
|
4304
|
-
"The pipeline produces **notes and
|
|
4305
|
-
"
|
|
4306
|
-
"
|
|
4307
|
-
"
|
|
4308
|
-
"
|
|
4309
|
-
"pipeline stays generic.",
|
|
5492
|
+
"The pipeline produces **profiles, notes, and matrix rows only**.",
|
|
5493
|
+
"Deeper research on adjacent products is delegated to new cycles of",
|
|
5494
|
+
"this same pipeline via follow-up issues. This agent never writes",
|
|
5495
|
+
"company profiles, person profiles, formal requirement documents, or",
|
|
5496
|
+
"comparative long-form analyses itself. Keep this boundary clean so",
|
|
5497
|
+
"the software-profile pipeline stays generic.",
|
|
4310
5498
|
"",
|
|
4311
5499
|
"---",
|
|
4312
5500
|
"",
|
|
4313
5501
|
"## Rules",
|
|
4314
5502
|
"",
|
|
4315
|
-
"- **One
|
|
4316
|
-
" single session.",
|
|
5503
|
+
"- **One product per session.** Never profile two products back-to-back.",
|
|
4317
5504
|
"- **Persist before closing.** Every phase must write its output file",
|
|
4318
5505
|
" before closing its issue.",
|
|
4319
|
-
"- **
|
|
4320
|
-
"
|
|
4321
|
-
"
|
|
4322
|
-
"-
|
|
4323
|
-
"
|
|
4324
|
-
"
|
|
4325
|
-
"
|
|
4326
|
-
"
|
|
4327
|
-
"
|
|
5506
|
+
"- **Cite everything.** Profile claims without source citations do not",
|
|
5507
|
+
" belong in the deliverable.",
|
|
5508
|
+
"- **No invented weights.** Segment weights come from",
|
|
5509
|
+
" `docs/project-context.md` or an explicit issue-body override. If",
|
|
5510
|
+
" neither is available, fall back to the single-segment default and",
|
|
5511
|
+
" flag the gap \u2014 never guess.",
|
|
5512
|
+
"- **Produce profiles and matrix rows, not downstream work.** Do not",
|
|
5513
|
+
" open `type:requirement` or formal evaluation issues from this",
|
|
5514
|
+
" pipeline. Follow-up work is scoped through `software:followup` or",
|
|
5515
|
+
" delegated to downstream research agents."
|
|
4328
5516
|
].join("\n")
|
|
4329
5517
|
};
|
|
4330
|
-
var
|
|
4331
|
-
name: "
|
|
4332
|
-
description: "Kick off a
|
|
5518
|
+
var profileSoftwareSkill = {
|
|
5519
|
+
name: "profile-software",
|
|
5520
|
+
description: "Kick off a software-profile pipeline. Creates a software:research issue for the given product and dispatches Phase 1 (Research) in the software-profile-analyst agent.",
|
|
4333
5521
|
disableModelInvocation: true,
|
|
4334
5522
|
userInvocable: true,
|
|
4335
5523
|
context: "fork",
|
|
4336
|
-
agent: "
|
|
5524
|
+
agent: "software-profile-analyst",
|
|
4337
5525
|
platforms: { cursor: { exclude: true } },
|
|
4338
5526
|
instructions: [
|
|
4339
|
-
"#
|
|
5527
|
+
"# Profile Software",
|
|
4340
5528
|
"",
|
|
4341
|
-
"Kick off a
|
|
4342
|
-
"
|
|
4343
|
-
"Phase 1 (
|
|
5529
|
+
"Kick off a software-profile pipeline. Creates a `software:research`",
|
|
5530
|
+
"issue carrying the product name, type, and framing, then dispatches",
|
|
5531
|
+
"Phase 1 (Research) in the software-profile-analyst agent.",
|
|
4344
5532
|
"",
|
|
4345
5533
|
"## Usage",
|
|
4346
5534
|
"",
|
|
4347
|
-
"/
|
|
5535
|
+
"/profile-software <product-name>",
|
|
4348
5536
|
"",
|
|
4349
|
-
"Optional extensions in the
|
|
4350
|
-
"- `
|
|
4351
|
-
"
|
|
4352
|
-
"
|
|
4353
|
-
"- `
|
|
4354
|
-
"
|
|
5537
|
+
"Optional extensions in the issue body:",
|
|
5538
|
+
"- `type: <competitor | adjacent | incumbent | enabler |",
|
|
5539
|
+
" infrastructure | ecosystem-tool>` \u2014 override the default type",
|
|
5540
|
+
" inference",
|
|
5541
|
+
"- `website: <url>` \u2014 canonical website if not obvious from the name",
|
|
5542
|
+
"- `framing: <text>` \u2014 why this profile was requested and what to learn",
|
|
5543
|
+
"- `slug: <kebab-case>` \u2014 override the derived product slug",
|
|
5544
|
+
"- `weights: <table>` \u2014 override the segment-importance weights for",
|
|
5545
|
+
" this profile cycle (otherwise loaded from",
|
|
5546
|
+
" `docs/project-context.md`)",
|
|
5547
|
+
"- `sources: <list>` \u2014 additional authorized sources beyond public web",
|
|
4355
5548
|
"",
|
|
4356
5549
|
"## Default Paths",
|
|
4357
5550
|
"",
|
|
4358
5551
|
"If the project has no override in `docs/project-context.md` or",
|
|
4359
5552
|
"`agentConfig.rules`, outputs land under:",
|
|
4360
5553
|
"",
|
|
4361
|
-
"- `docs/
|
|
4362
|
-
"- `docs/
|
|
4363
|
-
"- `docs/
|
|
4364
|
-
"- `docs/research/deliverables/<slug>.verify.md`",
|
|
5554
|
+
"- `docs/software/notes/<slug>.notes.md`",
|
|
5555
|
+
"- `docs/software/profiles/<slug>.md`",
|
|
5556
|
+
"- `docs/software/feature-matrix.md` (shared across all products)",
|
|
4365
5557
|
"",
|
|
4366
5558
|
"## Steps",
|
|
4367
5559
|
"",
|
|
4368
|
-
"1. Create a `research
|
|
5560
|
+
"1. Create a `software:research` issue with `type:software-profile`,",
|
|
4369
5561
|
" `priority:medium`, and `status:ready`. Body must include the",
|
|
4370
|
-
"
|
|
4371
|
-
"2. Execute Phase 1 (
|
|
4372
|
-
"
|
|
4373
|
-
"
|
|
4374
|
-
"
|
|
5562
|
+
" product name, selected type, framing, and any overrides.",
|
|
5563
|
+
"2. Execute Phase 1 (Research) of the software-profile-analyst",
|
|
5564
|
+
" agent.",
|
|
5565
|
+
"3. Phase 1 creates the `software:profile` issue. Phase 2 creates",
|
|
5566
|
+
" the `software:matrix` issue. Phase 3 may create a",
|
|
5567
|
+
" `software:followup` issue. Each downstream issue declares its",
|
|
5568
|
+
" `Depends on:` predecessor.",
|
|
4375
5569
|
"",
|
|
4376
5570
|
"## Output",
|
|
4377
5571
|
"",
|
|
4378
|
-
"- A
|
|
4379
|
-
"-
|
|
4380
|
-
"-
|
|
4381
|
-
"
|
|
4382
|
-
"-
|
|
4383
|
-
"
|
|
5572
|
+
"- A research-notes file under the project's notes directory",
|
|
5573
|
+
"- A single software profile under the profiles directory",
|
|
5574
|
+
"- One or more rows appended to the shared feature-matrix file,",
|
|
5575
|
+
" scored against the configured segment weights",
|
|
5576
|
+
"- Optional follow-up research issues for adjacent products",
|
|
5577
|
+
" surfaced in the profile",
|
|
5578
|
+
"- This pipeline produces **profiles, notes, and matrix rows only**",
|
|
5579
|
+
" \u2014 it does not write company profiles, person profiles, or formal",
|
|
5580
|
+
" requirement documents itself."
|
|
4384
5581
|
].join("\n")
|
|
4385
5582
|
};
|
|
4386
|
-
var
|
|
4387
|
-
name: "
|
|
4388
|
-
description: "
|
|
5583
|
+
var softwareProfileBundle = {
|
|
5584
|
+
name: "software-profile",
|
|
5585
|
+
description: "Software research, profiling, and feature-matrix pipeline: research, profile, matrix, followup. Opt-in only; domain-neutral; filesystem-durable between phases; ranks features against configurable segment-importance weights.",
|
|
4389
5586
|
appliesWhen: () => false,
|
|
4390
5587
|
rules: [
|
|
4391
5588
|
{
|
|
4392
|
-
name: "
|
|
4393
|
-
description: "Describes the
|
|
5589
|
+
name: "software-profile-workflow",
|
|
5590
|
+
description: "Describes the 4-phase software-profile pipeline, the software:* label taxonomy, the generic software-type taxonomy, and the segment-weights convention that drives feature-matrix scoring.",
|
|
4394
5591
|
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
4395
5592
|
content: [
|
|
4396
|
-
"#
|
|
4397
|
-
"",
|
|
4398
|
-
"Use `/
|
|
4399
|
-
"
|
|
4400
|
-
"
|
|
4401
|
-
"
|
|
4402
|
-
"
|
|
4403
|
-
"",
|
|
4404
|
-
"
|
|
4405
|
-
"
|
|
4406
|
-
"
|
|
4407
|
-
"
|
|
4408
|
-
"",
|
|
4409
|
-
"
|
|
4410
|
-
"
|
|
5593
|
+
"# Software Profile Workflow",
|
|
5594
|
+
"",
|
|
5595
|
+
"Use `/profile-software <product-name>` to kick off a software",
|
|
5596
|
+
"research, profiling, and feature-matrix pipeline. The pipeline",
|
|
5597
|
+
"runs in up to 4 phases \u2014 research, profile, matrix, followup \u2014",
|
|
5598
|
+
"each tracked by its own GitHub issue labeled",
|
|
5599
|
+
"`software:research`, `software:profile`, `software:matrix`, or",
|
|
5600
|
+
"`software:followup`. All issues carry `type:software-profile`.",
|
|
5601
|
+
"",
|
|
5602
|
+
"The pipeline produces **software profiles, research notes, and",
|
|
5603
|
+
"rows in a shared feature matrix**. Features are ranked against",
|
|
5604
|
+
"segment-importance weights declared in",
|
|
5605
|
+
"`docs/project-context.md` under a `## Segment Weights` section.",
|
|
5606
|
+
"Deeper research on adjacent products surfaced in a profile is",
|
|
5607
|
+
"delegated to new cycles of this same pipeline via",
|
|
5608
|
+
"`software:followup` issues.",
|
|
5609
|
+
"",
|
|
5610
|
+
"See the `software-profile-analyst` agent definition for full",
|
|
5611
|
+
"workflow details, default paths, the software-type taxonomy,",
|
|
5612
|
+
"the segment-weights convention, and phase-by-phase",
|
|
5613
|
+
"instructions."
|
|
4411
5614
|
].join("\n"),
|
|
4412
5615
|
platforms: {
|
|
4413
5616
|
cursor: { exclude: true }
|
|
@@ -4415,68 +5618,33 @@ var researchPipelineBundle = {
|
|
|
4415
5618
|
tags: ["workflow"]
|
|
4416
5619
|
}
|
|
4417
5620
|
],
|
|
4418
|
-
skills: [
|
|
4419
|
-
subAgents: [
|
|
5621
|
+
skills: [profileSoftwareSkill],
|
|
5622
|
+
subAgents: [softwareProfileAnalystSubAgent],
|
|
4420
5623
|
labels: [
|
|
4421
5624
|
{
|
|
4422
|
-
name: "type:
|
|
4423
|
-
color: "
|
|
4424
|
-
description: "Work that produces or
|
|
5625
|
+
name: "type:software-profile",
|
|
5626
|
+
color: "0E8A16",
|
|
5627
|
+
description: "Work that produces or maintains a software profile, research notes, or feature-matrix rows"
|
|
4425
5628
|
},
|
|
4426
5629
|
{
|
|
4427
|
-
name: "research
|
|
5630
|
+
name: "software:research",
|
|
4428
5631
|
color: "C5DEF5",
|
|
4429
|
-
description: "Phase 1:
|
|
5632
|
+
description: "Phase 1: gather public sources about a software product into a research-notes file"
|
|
4430
5633
|
},
|
|
4431
5634
|
{
|
|
4432
|
-
name: "
|
|
5635
|
+
name: "software:profile",
|
|
4433
5636
|
color: "BFDADC",
|
|
4434
|
-
description: "Phase 2:
|
|
5637
|
+
description: "Phase 2: write the structured software profile from research notes"
|
|
4435
5638
|
},
|
|
4436
5639
|
{
|
|
4437
|
-
name: "
|
|
5640
|
+
name: "software:matrix",
|
|
4438
5641
|
color: "D4C5F9",
|
|
4439
|
-
description: "Phase 3:
|
|
4440
|
-
}
|
|
4441
|
-
]
|
|
4442
|
-
};
|
|
4443
|
-
|
|
4444
|
-
// src/agent/bundles/slack.ts
|
|
4445
|
-
var slackBundle = {
|
|
4446
|
-
name: "slack",
|
|
4447
|
-
description: "Slack MCP message formatting and best practices",
|
|
4448
|
-
appliesWhen: () => false,
|
|
4449
|
-
rules: [
|
|
5642
|
+
description: "Phase 3: extract feature rows into the shared feature matrix and score them against segment weights"
|
|
5643
|
+
},
|
|
4450
5644
|
{
|
|
4451
|
-
name: "
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
content: [
|
|
4455
|
-
"# Slack Message Formatting",
|
|
4456
|
-
"",
|
|
4457
|
-
"When composing or sending messages to Slack (e.g., via Slack MCP tools like `slack_send_message`), use formatting that Slack's mrkdwn parser renders correctly.",
|
|
4458
|
-
"",
|
|
4459
|
-
"## Rules",
|
|
4460
|
-
"",
|
|
4461
|
-
"1. **Use Slack's explicit link syntax** for any link in a message:",
|
|
4462
|
-
" - Format: `<https://example.com|display text>`",
|
|
4463
|
-
" - Text outside the angle brackets (bullets, labels) stays separate and won't merge into the link",
|
|
4464
|
-
"",
|
|
4465
|
-
"2. **Do not rely on auto-linkification** when the message has bullets or labels before URLs \u2014 auto-linked URLs can break or merge with surrounding text",
|
|
4466
|
-
"",
|
|
4467
|
-
"3. **Put each list item on its own line** with a newline between items so list structure is clear",
|
|
4468
|
-
"",
|
|
4469
|
-
"4. **Example \u2014 preferred:**",
|
|
4470
|
-
" ```",
|
|
4471
|
-
" Status update:",
|
|
4472
|
-
"",
|
|
4473
|
-
" \u2022 Feature A: <https://github.com/org/repo/pull/1|repo#1>",
|
|
4474
|
-
" \u2022 Feature B: <https://github.com/org/repo/pull/2|repo#2>",
|
|
4475
|
-
" ```",
|
|
4476
|
-
"",
|
|
4477
|
-
"5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `\u2022 Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links"
|
|
4478
|
-
].join("\n"),
|
|
4479
|
-
tags: ["workflow"]
|
|
5645
|
+
name: "software:followup",
|
|
5646
|
+
color: "FBCA04",
|
|
5647
|
+
description: "Phase 4: enqueue follow-up research issues for adjacent products surfaced in the profile"
|
|
4480
5648
|
}
|
|
4481
5649
|
]
|
|
4482
5650
|
};
|
|
@@ -5093,7 +6261,9 @@ var BUILT_IN_BUNDLES = [
|
|
|
5093
6261
|
prReviewBundle,
|
|
5094
6262
|
requirementsAnalystBundle,
|
|
5095
6263
|
researchPipelineBundle,
|
|
5096
|
-
companyProfileBundle
|
|
6264
|
+
companyProfileBundle,
|
|
6265
|
+
peopleProfileBundle,
|
|
6266
|
+
softwareProfileBundle
|
|
5097
6267
|
];
|
|
5098
6268
|
|
|
5099
6269
|
// src/agent/bundles/scope.ts
|
|
@@ -8619,6 +9789,7 @@ var TypeScriptConfig = class extends import_projen22.Component {
|
|
|
8619
9789
|
jestBundle,
|
|
8620
9790
|
meetingAnalysisBundle,
|
|
8621
9791
|
orchestratorBundle,
|
|
9792
|
+
peopleProfileBundle,
|
|
8622
9793
|
pnpmBundle,
|
|
8623
9794
|
prReviewBundle,
|
|
8624
9795
|
projenBundle,
|
|
@@ -8627,6 +9798,7 @@ var TypeScriptConfig = class extends import_projen22.Component {
|
|
|
8627
9798
|
resolveModelAlias,
|
|
8628
9799
|
resolveTemplateVariables,
|
|
8629
9800
|
slackBundle,
|
|
9801
|
+
softwareProfileBundle,
|
|
8630
9802
|
turborepoBundle,
|
|
8631
9803
|
typescriptBundle,
|
|
8632
9804
|
vitestBundle
|