@gh-symphony/cli 0.4.0 → 0.4.1

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.
@@ -16,7 +16,7 @@ import {
16
16
  formatClaudePreflightText,
17
17
  resolveClaudeCommandBinary,
18
18
  runClaudePreflight
19
- } from "./chunk-6OPRRC2J.js";
19
+ } from "./chunk-YKC6CGD6.js";
20
20
 
21
21
  // src/mapping/smart-defaults.ts
22
22
  var ROLE_PATTERNS = [
@@ -97,8 +97,17 @@ function validateStateMapping(mappings) {
97
97
  import * as p from "@clack/prompts";
98
98
  import { spawnSync } from "child_process";
99
99
  import { createHash } from "crypto";
100
- import { chmod, mkdir as mkdir3, readFile as readFile3, rename as rename2, writeFile as writeFile3 } from "fs/promises";
101
- import { dirname as dirname3, join as join3, relative, resolve } from "path";
100
+ import {
101
+ chmod,
102
+ mkdir as mkdir2,
103
+ readFile as readFile3,
104
+ readdir as readdir2,
105
+ rename as rename2,
106
+ rm,
107
+ rmdir,
108
+ writeFile as writeFile2
109
+ } from "fs/promises";
110
+ import { dirname as dirname2, join as join3, relative, resolve } from "path";
102
111
 
103
112
  // src/prompts/runtime-claude-constraints.ts
104
113
  var CLAUDE_RUNTIME_CONSTRAINTS_SECTION = `## Runtime Constraints
@@ -209,7 +218,6 @@ function buildRepositoryValidationGuidance(input) {
209
218
  // src/workflow/workflow-runtime.ts
210
219
  var CODEX_RUNTIME_TOKENS = ["codex-app-server", "codex"];
211
220
  var CLAUDE_RUNTIME_TOKENS = ["claude-print", "claude-code"];
212
- var DEFAULT_CODEX_APP_SERVER_ARGS = ["app-server"];
213
221
  var DEFAULT_CLAUDE_PRINT_ARGS = [
214
222
  "-p",
215
223
  "--output-format",
@@ -258,31 +266,6 @@ function resolveRuntimeCommand(runtime) {
258
266
  }
259
267
  return runtime;
260
268
  }
261
- function resolveRuntimeArgs(runtime) {
262
- const normalized = normalizeInitRuntime(runtime);
263
- if (normalized === "codex-app-server") {
264
- return DEFAULT_CODEX_APP_SERVER_ARGS;
265
- }
266
- if (normalized === "claude-print") {
267
- return DEFAULT_CLAUDE_PRINT_ARGS;
268
- }
269
- return [];
270
- }
271
- function resolveRuntimeAgentCommand(runtime) {
272
- const command = resolveRuntimeCommand(runtime);
273
- const args = resolveRuntimeArgs(runtime);
274
- return args.length === 0 ? command : [command, ...args].join(" ");
275
- }
276
- function resolveShellAgentCommand(runtime) {
277
- if (/^\s*bash\s+-lc\s+/.test(runtime)) {
278
- return runtime;
279
- }
280
- const normalized = normalizeInitRuntime(runtime);
281
- if (normalized === "codex-app-server" || normalized === "claude-print") {
282
- return `bash -lc ${resolveRuntimeAgentCommand(normalized)}`;
283
- }
284
- return runtime;
285
- }
286
269
  function buildRuntimeFrontMatter(runtime) {
287
270
  const normalized = normalizeInitRuntime(runtime);
288
271
  if (normalized === "codex-app-server") {
@@ -833,1129 +816,991 @@ async function detectEnvironment(cwd) {
833
816
  };
834
817
  }
835
818
 
836
- // src/context/generate-context-yaml.ts
837
- import { mkdir, writeFile } from "fs/promises";
838
- import { dirname } from "path";
839
- function yamlQuote(value) {
840
- const specialChars = /[:#{'"\]{}()\\[]|\n/;
841
- if (specialChars.test(value)) {
842
- return `"${value.replace(/"/g, '\\"')}"`;
819
+ // src/skills/skill-writer.ts
820
+ import { mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
821
+ import { dirname, join as join2 } from "path";
822
+ function normalizeRuntimeForSkills(runtime) {
823
+ if (isClaudeRuntime(runtime)) {
824
+ return "claude-code";
825
+ }
826
+ if (isCodexRuntime(runtime)) {
827
+ return "codex";
843
828
  }
844
- return value;
829
+ return null;
845
830
  }
846
- function generateContextYamlString(context) {
847
- const lines = [];
848
- lines.push("schema_version: 1");
849
- lines.push(`collected_at: ${context.collected_at}`);
850
- lines.push("");
851
- lines.push("project:");
852
- lines.push(` id: ${context.project.id}`);
853
- lines.push(` title: ${yamlQuote(context.project.title)}`);
854
- lines.push(` url: ${context.project.url}`);
855
- lines.push("");
856
- lines.push("status_field:");
857
- lines.push(` id: ${context.status_field.id}`);
858
- lines.push(` name: ${yamlQuote(context.status_field.name)}`);
859
- lines.push(" columns:");
860
- for (const column of context.status_field.columns) {
861
- lines.push(` - id: ${column.id}`);
862
- lines.push(` name: ${yamlQuote(column.name)}`);
863
- lines.push(
864
- ` color: ${column.color === null ? "null" : yamlQuote(column.color)}`
865
- );
866
- lines.push(
867
- ` inferred_role: ${column.inferred_role === null ? "null" : column.inferred_role}`
868
- );
869
- lines.push(` confidence: ${column.confidence}`);
831
+ function resolveSkillsDir(repoRoot, runtime) {
832
+ const normalizedRuntime = normalizeRuntimeForSkills(runtime);
833
+ if (normalizedRuntime === "claude-code") {
834
+ return join2(repoRoot, ".claude", "skills");
870
835
  }
871
- lines.push("");
872
- lines.push("text_fields:");
873
- if (context.text_fields.length === 0) {
874
- lines.push(" []");
875
- } else {
876
- for (const field of context.text_fields) {
877
- lines.push(` - id: ${field.id}`);
878
- lines.push(` name: ${yamlQuote(field.name)}`);
879
- lines.push(` data_type: ${field.data_type}`);
880
- }
836
+ if (normalizedRuntime === "codex") {
837
+ return join2(repoRoot, ".codex", "skills");
881
838
  }
882
- lines.push("");
883
- lines.push("repositories:");
884
- if (context.repositories.length === 0) {
885
- lines.push(" []");
886
- } else {
887
- for (const repo of context.repositories) {
888
- lines.push(` - owner: ${repo.owner}`);
889
- lines.push(` name: ${repo.name}`);
890
- lines.push(` clone_url: ${repo.clone_url}`);
891
- }
839
+ return null;
840
+ }
841
+ function buildSkillFilePlans(repoRoot, runtime, templates, context) {
842
+ const skillsDir = resolveSkillsDir(repoRoot, runtime);
843
+ if (!skillsDir) {
844
+ return { skillsDir: null, files: [] };
892
845
  }
846
+ return {
847
+ skillsDir,
848
+ files: templates.flatMap(
849
+ (template) => template.files.map((file) => ({
850
+ path: join2(skillsDir, template.name, file.relativePath),
851
+ content: file.generate(context)
852
+ }))
853
+ )
854
+ };
855
+ }
856
+
857
+ // src/skills/templates/document.ts
858
+ function renderSkillDocument(options) {
859
+ const { name, description, bodyLines } = options;
860
+ return [
861
+ "---",
862
+ `name: ${name}`,
863
+ `description: ${description}`,
864
+ "license: MIT",
865
+ "metadata:",
866
+ " author: gh-symphony",
867
+ ' version: "1.0"',
868
+ ' generatedBy: "gh-symphony"',
869
+ "---",
870
+ "",
871
+ ...bodyLines
872
+ ].join("\n");
873
+ }
874
+
875
+ // src/skills/templates/gh-symphony.ts
876
+ function generateGhSymphonySkill(ctx) {
877
+ const lines = [];
878
+ lines.push("# /gh-symphony \u2014 WORKFLOW.md Design & Refinement");
879
+ lines.push("");
880
+ lines.push("## Trigger");
881
+ lines.push("");
882
+ lines.push("Use this skill when you want to:");
883
+ lines.push("- Create a new WORKFLOW.md for a GitHub Symphony project");
884
+ lines.push("- Refine or improve an existing WORKFLOW.md");
885
+ lines.push("- Validate that a WORKFLOW.md is correctly structured");
886
+ lines.push("");
887
+ lines.push("## Prerequisites");
888
+ lines.push("");
889
+ lines.push("- `WORKFLOW.md` is the repository policy and config source");
890
+ lines.push("- `references/README.md` must exist beside this skill");
891
+ lines.push("- `gh` CLI must be authenticated");
892
+ lines.push("");
893
+ lines.push("## Repository Validation Guidance");
893
894
  lines.push("");
894
- lines.push("detected_environment:");
895
895
  lines.push(
896
- ` packageManager: ${context.detected_environment.packageManager === null ? "null" : yamlQuote(context.detected_environment.packageManager)}`
896
+ "Carry the detected repository validation posture into any new or refined `WORKFLOW.md` instead of falling back to generic instructions."
897
897
  );
898
+ for (const line of buildRepositoryValidationGuidance(
899
+ ctx.detectedEnvironment
900
+ )) {
901
+ lines.push(`- ${line}`);
902
+ }
903
+ lines.push("");
904
+ lines.push("## Mode Detection");
905
+ lines.push("");
906
+ lines.push("Check if `WORKFLOW.md` exists in the current directory:");
907
+ lines.push("- **Not found** \u2192 enter **Design Mode** (create from scratch)");
908
+ lines.push("- **Found** \u2192 ask user: refine existing or validate only?");
909
+ lines.push(" - Refine \u2192 enter **Refine Mode**");
910
+ lines.push(" - Validate \u2192 enter **Validate Mode**");
911
+ lines.push("");
912
+ lines.push("## Design Mode");
913
+ lines.push("");
898
914
  lines.push(
899
- ` lockfile: ${context.detected_environment.lockfile === null ? "null" : yamlQuote(context.detected_environment.lockfile)}`
915
+ "1. Read `WORKFLOW.md` if it exists and extract repository conventions:"
900
916
  );
917
+ lines.push(" - test / lint / build commands from the prompt body");
918
+ lines.push(" - lifecycle states from front matter");
901
919
  lines.push(
902
- ` testCommand: ${context.detected_environment.testCommand === null ? "null" : yamlQuote(context.detected_environment.testCommand)}`
920
+ "2. Read `references/README.md` for the available reference files."
903
921
  );
922
+ lines.push('3. Ask the user: "What should this orchestration accomplish?"');
923
+ lines.push(" - implement (default) \u2014 write features / fix bugs");
924
+ lines.push(" - review \u2014 review PRs and leave comments");
925
+ lines.push(" - maintain \u2014 dependency bumps, chores, hygiene");
926
+ lines.push(" - custom \u2014 describe in their own words");
904
927
  lines.push(
905
- ` buildCommand: ${context.detected_environment.buildCommand === null ? "null" : yamlQuote(context.detected_environment.buildCommand)}`
928
+ "4. Pick the matching `references/workflow-posture-*.md` file(s); compose multiple files when the intent spans categories."
906
929
  );
930
+ lines.push("5. Ask these setup questions:");
931
+ lines.push(" - Which status columns should be **active** (agent works)?");
932
+ lines.push(" - Which should be **wait** (agent pauses for human)?");
933
+ lines.push(" - Which should be **terminal** (agent stops)?");
934
+ lines.push(" - What runtime is being used? (codex / claude-code / custom)");
935
+ lines.push(" - Any custom hooks needed? (after_create, before_run, etc.)");
936
+ lines.push("6. Generate WORKFLOW.md:");
937
+ lines.push(" - front matter from `references/workflow-schema.md`");
907
938
  lines.push(
908
- ` lintCommand: ${context.detected_environment.lintCommand === null ? "null" : yamlQuote(context.detected_environment.lintCommand)}`
939
+ " - prompt body from the selected posture file(s), adapted to actual repository commands"
909
940
  );
941
+ lines.push("7. Show a diff or preview and confirm with the user.");
942
+ lines.push("8. Validate via `gh-symphony workflow validate`.");
943
+ lines.push("");
944
+ lines.push("## Refine Mode");
945
+ lines.push("");
946
+ lines.push("1. Read the current `WORKFLOW.md`");
910
947
  lines.push(
911
- ` ciPlatform: ${context.detected_environment.ciPlatform === null ? "null" : yamlQuote(context.detected_environment.ciPlatform)}`
948
+ "2. Read `references/README.md` and select the relevant posture file(s)"
912
949
  );
913
- lines.push(` monorepo: ${context.detected_environment.monorepo}`);
914
- lines.push(" existingSkills:");
915
- if (context.detected_environment.existingSkills.length === 0) {
916
- lines.push(" []");
917
- } else {
918
- for (const skill of context.detected_environment.existingSkills) {
919
- lines.push(` - ${yamlQuote(skill)}`);
920
- }
921
- }
922
- lines.push("");
923
- lines.push("runtime:");
924
- lines.push(` agent: ${yamlQuote(context.runtime.agent)}`);
925
- lines.push(` agent_command: ${yamlQuote(context.runtime.agent_command)}`);
926
- return lines.join("\n") + "\n";
927
- }
928
- function buildContextYaml(params) {
929
- const columns = params.statusField.options.map((option) => {
930
- const roleMapping = inferStateRole(option.name);
931
- return {
932
- id: option.id,
933
- name: option.name,
934
- color: option.color,
935
- inferred_role: roleMapping.role,
936
- confidence: roleMapping.confidence
937
- };
938
- });
939
- const textFields = params.projectDetail.textFields.map((field) => ({
940
- id: field.id,
941
- name: field.name,
942
- data_type: field.dataType
943
- }));
944
- const repositories = params.projectDetail.linkedRepositories.map((repo) => ({
945
- owner: repo.owner,
946
- name: repo.name,
947
- clone_url: repo.cloneUrl
948
- }));
949
- return {
950
- schema_version: 1,
951
- collected_at: (/* @__PURE__ */ new Date()).toISOString(),
952
- project: {
953
- id: params.projectDetail.id,
954
- title: params.projectDetail.title,
955
- url: params.projectDetail.url
956
- },
957
- status_field: {
958
- id: params.statusField.id,
959
- name: params.statusField.name,
960
- columns
961
- },
962
- text_fields: textFields,
963
- repositories,
964
- detected_environment: params.detectedEnvironment,
965
- runtime: params.runtime
966
- };
967
- }
968
-
969
- // src/workflow/generate-reference-workflow.ts
970
- function generateReferenceWorkflow(input) {
971
- const lines = [];
972
- lines.push("# Reference WORKFLOW.md \u2014 gh-symphony");
973
- lines.push("# This file is a reference template for authoring WORKFLOW.md.");
974
950
  lines.push(
975
- "# AI agents reference this file (via the /gh-symphony skill) when designing WORKFLOW.md."
951
+ "3. Compare the current prompt body against the selected posture references"
976
952
  );
977
- lines.push("# Do not edit this file directly.");
953
+ lines.push("4. Identify missing or incomplete sections:");
954
+ lines.push(" - Status Map with role annotations");
955
+ lines.push(" - Default Posture / Agent Instructions");
956
+ lines.push(" - Guardrails section");
957
+ lines.push(" - Workpad Template");
958
+ lines.push(" - Step 0 routing logic");
959
+ lines.push("5. Propose improvements and apply with user confirmation");
960
+ lines.push("6. Validate the refined file");
978
961
  lines.push("");
979
- lines.push("---");
962
+ lines.push("## Validate Mode");
980
963
  lines.push("");
981
- lines.push("# \u2550\u2550\u2550 FRONT MATTER FIELD REFERENCE \u2550\u2550\u2550");
964
+ lines.push("Check the WORKFLOW.md for:");
965
+ lines.push("- Front matter is valid YAML");
982
966
  lines.push(
983
- "# All front matter fields supported by the gh-symphony parser are listed below."
967
+ "- Required fields are present (see `references/workflow-schema.md`)"
984
968
  );
985
- lines.push("");
986
- lines.push("tracker:");
987
- lines.push(" kind: github-project");
988
- lines.push(` project_id: ${input.projectId}`);
989
- lines.push(" state_field: Status");
990
- lines.push(...buildReferencePriorityLines(input.priority));
991
- lines.push("");
992
- const activeColumns = input.statusColumns.filter((c) => c.role === "active");
993
- const waitColumns = input.statusColumns.filter((c) => c.role === "wait");
994
- const terminalColumns = input.statusColumns.filter(
995
- (c) => c.role === "terminal"
969
+ lines.push(
970
+ "- Template variables use only supported names (see `references/workflow-schema.md`)"
996
971
  );
997
- const blockerCheckStates = input.lifecycle?.blockerCheckStates ?? [];
998
- const planningStates = input.lifecycle?.planningStates ?? blockerCheckStates;
999
- if (activeColumns.length > 0) {
1000
- lines.push(" active_states:");
1001
- for (const col of activeColumns) {
1002
- lines.push(` - ${col.name}`);
1003
- }
1004
- } else {
1005
- lines.push(" active_states: [{active column names}]");
1006
- }
1007
- if (terminalColumns.length > 0) {
1008
- lines.push(" terminal_states:");
1009
- for (const col of terminalColumns) {
1010
- lines.push(` - ${col.name}`);
1011
- }
1012
- } else {
1013
- lines.push(" terminal_states: [{terminal column names}]");
1014
- }
972
+ lines.push("- Status Map matches the lifecycle configuration");
1015
973
  lines.push(
1016
- ...buildReferenceStringList("blocker_check_states", blockerCheckStates)
974
+ "- No unsupported double-brace variable patterns (only the 8 listed below are valid)"
1017
975
  );
1018
- lines.push(...buildReferenceStringList("planning_states", planningStates));
1019
- lines.push("");
1020
- lines.push("# Linear tracker example:");
1021
- lines.push("# tracker:");
1022
- lines.push("# kind: linear");
1023
- lines.push("# endpoint: https://api.linear.app/graphql");
1024
- lines.push("# api_key: $LINEAR_API_KEY");
1025
- lines.push("# project_slug: symphony-0c79b11b75ea");
1026
- lines.push("# active_states:");
1027
- lines.push("# - Todo");
1028
- lines.push("# - In Progress");
1029
- lines.push("# terminal_states:");
1030
- lines.push("# - Done");
1031
- lines.push("# - Canceled");
1032
- lines.push("# - Duplicate");
1033
976
  lines.push(
1034
- "# Linear uses repository-local polling; gh-symphony does not provide"
977
+ "- Prompt body posture is consistent with the selected `references/workflow-posture-*.md` file(s)"
1035
978
  );
1036
- lines.push("# a Linear webhook setup command.");
1037
979
  lines.push("");
980
+ lines.push("## Supported Front Matter Fields");
981
+ lines.push("");
982
+ lines.push("```yaml");
983
+ lines.push("tracker:");
984
+ lines.push(" kind: github-project");
985
+ lines.push(" project_id: PVT_xxx");
986
+ lines.push(" state_field: Status");
987
+ lines.push(" active_states: [Todo, In Progress]");
988
+ lines.push(" terminal_states: [Done, Cancelled]");
989
+ lines.push(" blocker_check_states: [Blocked]");
1038
990
  lines.push("polling:");
1039
991
  lines.push(" interval_ms: 30000");
1040
- lines.push("");
1041
992
  lines.push("workspace:");
1042
993
  lines.push(" root: .runtime/symphony-workspaces");
1043
- lines.push("");
1044
994
  lines.push("hooks:");
1045
- lines.push(
1046
- ` after_create: ${DEFAULT_AFTER_CREATE_HOOK_PATH} # ${DEFAULT_AFTER_CREATE_HOOK_COMMENT}`
1047
- );
995
+ lines.push(" after_create: |");
996
+ lines.push(" git clone --depth 1 https://github.com/owner/repo .");
1048
997
  lines.push(" before_run: null");
1049
998
  lines.push(" after_run: null");
1050
999
  lines.push(" before_remove: null");
1051
1000
  lines.push(" timeout_ms: 60000");
1052
- lines.push("");
1053
1001
  lines.push("agent:");
1054
1002
  lines.push(" max_concurrent_agents: 10");
1055
1003
  lines.push(" max_retry_backoff_ms: 30000");
1056
1004
  lines.push(" retry_base_delay_ms: 10000");
1057
1005
  lines.push(" max_turns: 20");
1006
+ lines.push("codex:");
1007
+ lines.push(" command: codex app-server");
1008
+ lines.push(" read_timeout_ms: 5000");
1009
+ lines.push(" turn_timeout_ms: 3600000");
1010
+ lines.push(" stall_timeout_ms: 300000");
1011
+ lines.push("```");
1058
1012
  lines.push("");
1059
- lines.push(...buildRuntimeFrontMatter(input.runtime));
1060
- lines.push("");
1061
- lines.push("---");
1013
+ lines.push("## Supported Template Variables");
1062
1014
  lines.push("");
1063
- lines.push("# \u2550\u2550\u2550 PROMPT BODY REFERENCE \u2550\u2550\u2550");
1064
- lines.push(
1065
- "# GitHub Project adaptation of the Elixir Symphony reference prompt."
1066
- );
1015
+ lines.push("Use these in the WORKFLOW.md prompt body (double-brace syntax):");
1067
1016
  lines.push("");
1068
- lines.push("## Status Map");
1069
- lines.push("");
1070
- lines.push("| Status | Role | Agent Action |");
1071
- lines.push("| ------ | ---- | ------------ |");
1072
- for (const col of input.statusColumns) {
1073
- const roleLabel = col.role ?? "unset";
1074
- const action = resolveRoleAction(col.role);
1075
- lines.push(`| ${col.name} | ${roleLabel} | ${action} |`);
1076
- }
1077
- if (waitColumns.length > 0) {
1078
- lines.push("");
1079
- lines.push("**Wait States (awaiting PR review):**");
1080
- for (const col of waitColumns) {
1081
- lines.push(
1082
- `- **${col.name}**: PR created. Awaiting human review. Agent is idle.`
1083
- );
1084
- }
1085
- }
1086
- lines.push("");
1087
- lines.push("## Repository Validation Guidance");
1088
- lines.push("");
1089
- for (const line of buildRepositoryValidationGuidance(
1090
- input.detectedEnvironment
1091
- )) {
1092
- lines.push(`- ${line}`);
1093
- }
1094
- lines.push("");
1095
- lines.push("## Default Posture");
1017
+ lines.push("| Variable | Description |");
1018
+ lines.push("|----------|-------------|");
1019
+ lines.push("| `issue.identifier` | e.g. `acme/platform#42` |");
1020
+ lines.push("| `issue.title` | Issue title |");
1021
+ lines.push("| `issue.state` | Current tracker state |");
1022
+ lines.push("| `issue.description` | Issue body |");
1023
+ lines.push("| `issue.url` | Issue URL |");
1024
+ lines.push("| `issue.repository` | `owner/name` |");
1025
+ lines.push("| `issue.number` | Issue number |");
1026
+ lines.push("| `attempt` | Retry attempt number (null on first run) |");
1096
1027
  lines.push("");
1097
1028
  lines.push(
1098
- "1. This is an unattended orchestration session. Do not ask humans for follow-up tasks."
1099
- );
1100
- lines.push(
1101
- "2. Exit early only for genuine blockers (missing required credentials or secrets)."
1102
- );
1103
- lines.push(
1104
- '3. In your final message, report only completed work and blockers. Do not include "next steps".'
1105
- );
1106
- lines.push(
1107
- "4. Do not modify the issue body for planning or progress-tracking purposes."
1108
- );
1109
- lines.push(
1110
- "5. If the issue is in a terminal state, do nothing and exit immediately."
1111
- );
1112
- lines.push(
1113
- "6. If you discover out-of-scope improvements, open a separate issue rather than expanding the current scope."
1114
- );
1115
- lines.push(
1116
- "7. Keep all commits as logical units and follow conventional commit format."
1117
- );
1118
- lines.push("8. Do not make commits that break existing tests.");
1119
- lines.push("9. Verify all existing tests pass before creating a PR.");
1120
- lines.push("10. Create a workpad as an issue comment to track progress.");
1121
- lines.push("11. Use the gh-project skill to manage issue status.");
1122
- lines.push(
1123
- "12. When a blocker is found, record it in an issue comment and transition the status appropriately."
1124
- );
1125
- lines.push(
1126
- "13. Once your work is complete and the PR is merged, transition the issue to the Done state."
1029
+ "**Important**: Only these 8 variables are supported. Using any other variable"
1127
1030
  );
1031
+ lines.push("will cause a runtime error (strict mode validation).");
1128
1032
  lines.push("");
1129
1033
  lines.push("## Related Skills");
1130
1034
  lines.push("");
1131
1035
  lines.push(
1132
- "- **gh-project**: Manage GitHub Project v2 issue status and update fields"
1036
+ "- `/gh-project` \u2014 interact with GitHub Project v2 board (status transitions, workpad comments)"
1133
1037
  );
1134
1038
  lines.push(
1135
- "- **commit**: Create logical-unit commits (conventional commit format)"
1039
+ "- `/commit` \u2014 produce clean, logical commits during implementation"
1136
1040
  );
1137
- lines.push("- **push**: Push branch and sync with the remote repository");
1138
- lines.push("- **pull**: Fetch latest changes and resolve conflicts");
1139
- lines.push("- **land**: Create PR, request review, and handle merge");
1041
+ lines.push("- `/push` \u2014 keep remote branch current and publish updates");
1042
+ lines.push("- `/pull` \u2014 sync branch with latest origin/main before handoff");
1043
+ lines.push("- `/land` \u2014 merge approved PR and transition issue to Done");
1044
+ return renderSkillDocument({
1045
+ name: "gh-symphony",
1046
+ description: "Design, refine, and validate repository WORKFLOW.md files for GitHub Symphony projects.",
1047
+ bodyLines: lines
1048
+ });
1049
+ }
1050
+
1051
+ // src/skills/templates/gh-project.ts
1052
+ function generateGhProjectSkill(ctx) {
1053
+ const lines = [];
1054
+ lines.push("# /gh-project \u2014 GitHub Project v2 Status Management");
1140
1055
  lines.push("");
1141
- lines.push("## Step 0: Determine current state and route");
1056
+ lines.push("## Purpose");
1142
1057
  lines.push("");
1143
1058
  lines.push(
1144
- "Check the current issue state and route to the appropriate step:"
1059
+ "Interact with the GitHub Project v2 board to manage issue status,"
1145
1060
  );
1061
+ lines.push("create workpad comments, and handle follow-up issues.");
1146
1062
  lines.push("");
1147
- if (terminalColumns.length > 0) {
1148
- const terminalNames = terminalColumns.map((c) => c.name).join(", ");
1149
- lines.push(`- **${terminalNames}** \u2192 Exit immediately. Do nothing.`);
1150
- }
1151
- if (waitColumns.length > 0) {
1152
- const waitNames = waitColumns.map((c) => c.name).join(", ");
1153
- lines.push(`- **${waitNames}** \u2192 Go to Step 3 (handle awaiting review).`);
1154
- }
1155
- if (activeColumns.length > 0) {
1156
- const activeNames = activeColumns.map((c) => c.name).join(", ");
1157
- lines.push(
1158
- `- **${activeNames}** \u2192 Go to Step 1 (start or continue execution).`
1159
- );
1160
- }
1063
+ lines.push("## Prerequisites");
1064
+ lines.push("");
1065
+ lines.push("- `gh` CLI is authenticated (`gh auth status`)");
1161
1066
  lines.push(
1162
- "- **Other states** \u2192 Log the unclear state in an issue comment and exit."
1067
+ "- This generated skill contains the status field and option IDs below"
1163
1068
  );
1164
1069
  lines.push("");
1165
- lines.push("## Step 1: Start/continue execution");
1070
+ lines.push("## Column ID Quick Reference");
1166
1071
  lines.push("");
1167
- lines.push(
1168
- "1. Read the issue body and comments to understand current progress."
1169
- );
1170
- lines.push(
1171
- "2. If an existing workpad comment is found, continue from it; otherwise create a new workpad."
1172
- );
1173
- lines.push(
1174
- "3. See the 'Workpad Template' section below for the workpad format."
1175
- );
1176
- lines.push(
1177
- "4. If no branch exists, create a feature branch based on `{issue.repository}`."
1178
- );
1179
- lines.push("5. Proceed to Step 2.");
1072
+ lines.push(`Status Field ID: \`${ctx.statusFieldId}\``);
1180
1073
  lines.push("");
1181
- lines.push("## Step 2: Execution phase");
1074
+ lines.push("| Column Name | Role | Option ID |");
1075
+ lines.push("|-------------|------|-----------|");
1076
+ for (const col of ctx.statusColumns) {
1077
+ const role = col.role ?? "unknown";
1078
+ lines.push(`| ${col.name} | ${role} | \`${col.id}\` |`);
1079
+ }
1182
1080
  lines.push("");
1183
- lines.push("1. Implement according to the issue description.");
1184
- lines.push(
1185
- "2. Commit changes in logical units (conventional commit format)."
1186
- );
1187
- lines.push("3. Verify all existing tests pass.");
1188
- lines.push("4. Write tests for new functionality.");
1189
- lines.push("5. Once all Completion Bar criteria are met, create a PR.");
1190
- lines.push(
1191
- "6. After creating the PR, transition the issue status to the Human Review state."
1192
- );
1193
- lines.push("7. Proceed to Step 3.");
1081
+ lines.push("## Operations");
1194
1082
  lines.push("");
1195
- lines.push("## Step 3: Human Review and merge handling");
1083
+ lines.push("### Change Issue Status");
1196
1084
  lines.push("");
1197
- lines.push("1. If a PR already exists, check for review comments.");
1198
- lines.push(
1199
- "2. If no review comments are present, remain in the waiting state."
1200
- );
1201
1085
  lines.push(
1202
- "3. If the PR is merged, transition the issue to a terminal state."
1086
+ "Use `gh project item-edit` with the field ID and option ID from the table above:"
1203
1087
  );
1204
- lines.push("4. If review changes are requested, proceed to Step 4.");
1205
- lines.push("");
1206
- lines.push("## Step 4: Rework handling");
1207
1088
  lines.push("");
1089
+ lines.push("```bash");
1090
+ lines.push("# Get the project item ID for an issue");
1208
1091
  lines.push(
1209
- "1. Read all PR review comments and identify the requested changes."
1092
+ "gh project item-list <project-number> --owner <owner> --format json \\"
1210
1093
  );
1211
1094
  lines.push(
1212
- "2. Process the changes following the PR Feedback Sweep Protocol."
1095
+ " | jq '.items[] | select(.content.number == <issue-number>) | .id'"
1213
1096
  );
1214
- lines.push("3. After implementing changes, commit and update the PR.");
1215
- lines.push("4. Transition the issue status back to the Human Review state.");
1216
- lines.push("5. Return to Step 3.");
1217
1097
  lines.push("");
1218
- lines.push("## PR Feedback Sweep Protocol");
1098
+ lines.push("# Update the status field");
1099
+ lines.push(`gh project item-edit \\`);
1100
+ lines.push(` --project-id ${ctx.projectId} \\`);
1101
+ lines.push(` --id <item-id> \\`);
1102
+ lines.push(` --field-id ${ctx.statusFieldId} \\`);
1103
+ lines.push(` --single-select-option-id <option-id-from-table-above>`);
1104
+ lines.push("```");
1219
1105
  lines.push("");
1220
- lines.push("Order for processing PR review feedback:");
1106
+ lines.push("### Create Workpad Comment");
1221
1107
  lines.push("");
1108
+ lines.push("```bash");
1222
1109
  lines.push(
1223
- "1. **Collect all comments**: List all unresolved review comments."
1224
- );
1225
- lines.push(
1226
- "2. **Triage by priority**: Handle blocking comments before non-blocking ones."
1227
- );
1228
- lines.push(
1229
- "3. **Implement changes**: Make the code changes corresponding to each comment."
1230
- );
1231
- lines.push(
1232
- "4. **Reply to comments**: Respond to each review comment with a description of what was done."
1110
+ 'gh issue comment <issue-number> --repo <owner>/<repo> --body "## Workpad\\n\\n### Plan\\n- [ ] Task 1"'
1233
1111
  );
1112
+ lines.push("```");
1113
+ lines.push("");
1114
+ lines.push("### Update Existing Comment");
1115
+ lines.push("");
1116
+ lines.push("```bash");
1234
1117
  lines.push(
1235
- "5. **Commit**: Commit changes in `fix: address PR review feedback` format."
1118
+ "gh api -X PATCH /repos/<owner>/<repo>/issues/comments/<comment-id> \\"
1236
1119
  );
1237
- lines.push("6. **Request re-review**: Ask the reviewer for a re-review.");
1120
+ lines.push(' -f body="## Workpad\\n\\n### Plan\\n- [x] Task 1 (done)"');
1121
+ lines.push("```");
1238
1122
  lines.push("");
1239
- lines.push("## Completion Bar");
1123
+ lines.push("### Create Follow-up Issue");
1240
1124
  lines.push("");
1241
- lines.push("All of the following must be satisfied before creating a PR:");
1125
+ lines.push("```bash");
1126
+ lines.push("gh issue create --repo <owner>/<repo> \\");
1127
+ lines.push(' --title "Follow-up: <title>" \\');
1128
+ lines.push(' --body "<description>" \\');
1129
+ lines.push(' --label "backlog"');
1130
+ lines.push("```");
1131
+ lines.push("");
1132
+ lines.push("### Add Label");
1242
1133
  lines.push("");
1134
+ lines.push("```bash");
1243
1135
  lines.push(
1244
- "- [ ] All requirements from the issue description are implemented."
1136
+ 'gh issue edit <issue-number> --repo <owner>/<repo> --add-label "<label>"'
1245
1137
  );
1246
- lines.push("- [ ] All existing tests pass.");
1247
- lines.push("- [ ] Tests are written for new functionality.");
1248
- lines.push("- [ ] Code style follows project conventions.");
1249
- lines.push("- [ ] The PR description clearly explains the changes.");
1250
- lines.push("- [ ] Related documentation is updated (if applicable).");
1138
+ lines.push("```");
1251
1139
  lines.push("");
1252
- lines.push("## Guardrails");
1140
+ lines.push("## Rules");
1253
1141
  lines.push("");
1254
- lines.push("- **Scope**: Never make changes outside the scope of the issue.");
1255
1142
  lines.push(
1256
- "- **Secrets**: Never hardcode tokens, passwords, or API keys in code."
1143
+ "- Always follow the WORKFLOW.md status map flow for state transitions"
1257
1144
  );
1258
1145
  lines.push(
1259
- "- **Breaking changes**: Do not modify existing APIs or interfaces without explicit authorization."
1146
+ "- Before transitioning to a terminal state, verify the Completion Bar is satisfied:"
1260
1147
  );
1261
- lines.push("- **Force push**: Do not force-push to the main/master branch.");
1148
+ lines.push(" - All acceptance criteria checked");
1149
+ lines.push(" - All tests passing");
1150
+ lines.push(" - PR merged (if applicable)");
1262
1151
  lines.push(
1263
- "- **Issue body**: Do not modify the issue body for progress tracking."
1152
+ "- Use the Column ID Quick Reference table above for all status transitions"
1264
1153
  );
1265
1154
  lines.push(
1266
- "- **Infinite loops**: If the same task fails 3 or more consecutive times, log it as a blocker and exit."
1155
+ "- Do not transition issues to terminal states without explicit completion verification"
1267
1156
  );
1157
+ return renderSkillDocument({
1158
+ name: "gh-project",
1159
+ description: "Manage GitHub Project v2 issue states, workpad comments, and related follow-up actions.",
1160
+ bodyLines: lines
1161
+ });
1162
+ }
1163
+
1164
+ // src/skills/templates/commit.ts
1165
+ function generateCommitSkill(_ctx) {
1166
+ const lines = [];
1167
+ lines.push("# /commit \u2014 Clean Commit Workflow");
1268
1168
  lines.push("");
1269
- lines.push("## Workpad Template");
1169
+ lines.push("## Trigger");
1270
1170
  lines.push("");
1271
- lines.push("Workpad format to create as an issue comment:");
1171
+ lines.push("Use this skill when creating commits during implementation.");
1272
1172
  lines.push("");
1273
- lines.push("```markdown");
1274
- lines.push("## Workpad \u2014 {issue.identifier}");
1173
+ lines.push("## Rules");
1275
1174
  lines.push("");
1276
- lines.push("**Status**: {current phase}");
1277
- lines.push("**Branch**: {branch name}");
1278
- lines.push("**PR**: {PR URL or not created}");
1279
- lines.push("");
1280
- lines.push("### Plan");
1175
+ lines.push("- Commit in logical units \u2014 one concern per commit");
1176
+ lines.push("- Never commit a broken intermediate state (tests must pass)");
1177
+ lines.push("- Never commit temporary debug code or commented-out blocks");
1178
+ lines.push("- Run tests before every commit");
1281
1179
  lines.push("");
1282
- lines.push("- [ ] {task 1}");
1283
- lines.push("- [ ] {task 2}");
1180
+ lines.push("## Format");
1284
1181
  lines.push("");
1285
- lines.push("### Progress Log");
1182
+ lines.push("Use Conventional Commit format:");
1286
1183
  lines.push("");
1287
- lines.push("- {timestamp}: {action taken}");
1184
+ lines.push("```");
1185
+ lines.push("<type>(<scope>): <description>");
1288
1186
  lines.push("");
1289
- lines.push("### Blockers");
1187
+ lines.push("[optional body \u2014 explain WHY, not WHAT, 72 chars/line]");
1290
1188
  lines.push("");
1291
- lines.push("None");
1189
+ lines.push("[optional footer: Closes #N]");
1292
1190
  lines.push("```");
1293
1191
  lines.push("");
1294
- return lines.join("\n");
1295
- }
1296
- function buildReferenceStringList(key, values) {
1297
- if (values.length === 0) {
1298
- return [` ${key}: []`];
1299
- }
1300
- return [` ${key}:`, ...values.map((value) => ` - ${value}`)];
1301
- }
1302
- function buildReferencePriorityLines(priority) {
1303
- const lines = [];
1304
- if (priority?.source === "project-field" || priority?.source === "labels") {
1305
- lines.push(
1306
- " # Priority is explicit. Numbers below are editable policy (lower = higher priority)."
1307
- );
1308
- } else {
1309
- lines.push(
1310
- " # Priority dispatch is disabled until an operator chooses one explicit source."
1311
- );
1312
- }
1192
+ lines.push("**Types**: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`");
1193
+ lines.push("");
1313
1194
  lines.push(
1314
- " # See docs/adr/2026-05-18_explicit-dispatch-priority-mappings.md"
1195
+ "**Description**: imperative mood, 50 chars max, no period at end"
1315
1196
  );
1316
- if (priority?.source === "project-field") {
1317
- lines.push(" priority:");
1318
- lines.push(" source: project-field");
1319
- lines.push(` field: ${JSON.stringify(priority.field)}`);
1320
- lines.push(" values:");
1321
- for (const [name, value] of Object.entries(priority.values)) {
1322
- lines.push(` ${JSON.stringify(name)}: ${value}`);
1323
- }
1324
- return lines;
1325
- }
1326
- if (priority?.source === "labels") {
1327
- lines.push(" priority:");
1328
- lines.push(" source: labels");
1329
- lines.push(" labels:");
1330
- for (const [name, value] of Object.entries(priority.labels)) {
1331
- lines.push(` ${JSON.stringify(name)}: ${value}`);
1332
- }
1333
- return lines;
1334
- }
1335
- lines.push(" priority:");
1336
- lines.push(" source: disabled");
1337
1197
  lines.push("");
1338
- lines.push(" # Optional template: project-field priority source.");
1339
- lines.push(" # priority:");
1340
- lines.push(" # source: project-field");
1341
- lines.push(" # field: Priority");
1342
- lines.push(" # values:");
1343
- lines.push(" # Urgent: 0");
1344
- lines.push(" # High: 1");
1198
+ lines.push("## Examples");
1345
1199
  lines.push("");
1346
- lines.push(" # Optional template: labels priority source.");
1347
- lines.push(" # priority:");
1348
- lines.push(" # source: labels");
1349
- lines.push(" # labels:");
1350
- lines.push(" # P0: 0");
1351
- lines.push(" # P1: 1");
1352
- return lines;
1353
- }
1354
- function resolveRoleAction(role) {
1355
- switch (role) {
1356
- case "active":
1357
- return "Agent starts work immediately. Creates workpad and proceeds with implementation.";
1358
- case "wait":
1359
- return "PR created. Awaiting human review. Agent is idle.";
1360
- case "terminal":
1361
- return "Completed state. Agent exits.";
1362
- case null:
1363
- return "Role unset. Must be explicitly configured in WORKFLOW.md.";
1364
- }
1365
- }
1366
-
1367
- // src/skills/skill-writer.ts
1368
- import { mkdir as mkdir2, readFile as readFile2, rename, writeFile as writeFile2 } from "fs/promises";
1369
- import { dirname as dirname2, join as join2 } from "path";
1370
- function normalizeRuntimeForSkills(runtime) {
1371
- if (isClaudeRuntime(runtime)) {
1372
- return "claude-code";
1373
- }
1374
- if (isCodexRuntime(runtime)) {
1375
- return "codex";
1376
- }
1377
- return null;
1378
- }
1379
- function resolveSkillsDir(repoRoot, runtime) {
1380
- const normalizedRuntime = normalizeRuntimeForSkills(runtime);
1381
- if (normalizedRuntime === "claude-code") {
1382
- return join2(repoRoot, ".claude", "skills");
1383
- }
1384
- if (normalizedRuntime === "codex") {
1385
- return join2(repoRoot, ".codex", "skills");
1386
- }
1387
- return null;
1388
- }
1389
- function buildSkillFilePlans(repoRoot, runtime, templates, context) {
1390
- const skillsDir = resolveSkillsDir(repoRoot, runtime);
1391
- if (!skillsDir) {
1392
- return { skillsDir: null, files: [] };
1393
- }
1394
- return {
1395
- skillsDir,
1396
- files: templates.flatMap(
1397
- (template) => template.files.map((file) => ({
1398
- path: join2(skillsDir, template.name, file.relativePath),
1399
- content: file.generate(context)
1400
- }))
1401
- )
1402
- };
1403
- }
1404
-
1405
- // src/skills/templates/document.ts
1406
- function renderSkillDocument(options) {
1407
- const { name, description, bodyLines } = options;
1408
- return [
1409
- "---",
1410
- `name: ${name}`,
1411
- `description: ${description}`,
1412
- "license: MIT",
1413
- "metadata:",
1414
- " author: gh-symphony",
1415
- ' version: "1.0"',
1416
- ' generatedBy: "gh-symphony"',
1417
- "---",
1418
- "",
1419
- ...bodyLines
1420
- ].join("\n");
1200
+ lines.push("```");
1201
+ lines.push("feat(auth): add OAuth2 token refresh");
1202
+ lines.push("fix(api): handle null response from upstream");
1203
+ lines.push("test(worker): add retry exhaustion coverage");
1204
+ lines.push("```");
1205
+ return renderSkillDocument({
1206
+ name: "commit",
1207
+ description: "Create clean, logically scoped commits that keep the repository in a shippable state.",
1208
+ bodyLines: lines
1209
+ });
1421
1210
  }
1422
1211
 
1423
- // src/skills/templates/gh-symphony.ts
1424
- function generateGhSymphonySkill(ctx) {
1212
+ // src/skills/templates/push.ts
1213
+ function generatePushSkill(_ctx) {
1425
1214
  const lines = [];
1426
- lines.push("# /gh-symphony \u2014 WORKFLOW.md Design & Refinement");
1215
+ lines.push("# /push \u2014 Git Push Workflow");
1427
1216
  lines.push("");
1428
1217
  lines.push("## Trigger");
1429
1218
  lines.push("");
1430
- lines.push("Use this skill when you want to:");
1431
- lines.push("- Create a new WORKFLOW.md for a GitHub Symphony project");
1432
- lines.push("- Refine or improve an existing WORKFLOW.md");
1433
- lines.push("- Validate that a WORKFLOW.md is correctly structured");
1219
+ lines.push(
1220
+ "Use this skill when publishing local commits to the remote branch."
1221
+ );
1434
1222
  lines.push("");
1435
- lines.push("## Prerequisites");
1223
+ lines.push("## Flow");
1224
+ lines.push("");
1225
+ lines.push("1. Run local tests and lint \u2014 ensure they pass before pushing");
1226
+ lines.push("2. Push to remote:");
1227
+ lines.push(" ```bash");
1228
+ lines.push(" git push origin <branch> # subsequent pushes");
1229
+ lines.push(" git push -u origin <branch> # first push (sets upstream)");
1230
+ lines.push(" ```");
1231
+ lines.push("3. If push is rejected (non-fast-forward):");
1232
+ lines.push(" - Run `git fetch origin && git merge origin/main`");
1233
+ lines.push(" - Resolve any conflicts");
1234
+ lines.push(" - Re-run tests");
1235
+ lines.push(" - Push again");
1236
+ lines.push("4. Record push result in workpad Notes");
1237
+ lines.push("");
1238
+ lines.push("## Rules");
1436
1239
  lines.push("");
1240
+ lines.push("- Never use `--force` (destructive)");
1437
1241
  lines.push(
1438
- `- \`${ctx.contextYamlPath}\` must exist (contains GitHub Project metadata)`
1242
+ "- Only use `--force-with-lease` if absolutely necessary \u2014 record the reason in workpad"
1439
1243
  );
1244
+ lines.push("- Verify CI starts after push (check GitHub Actions tab)");
1245
+ lines.push("- Do not push directly to `main` or `master`");
1246
+ return renderSkillDocument({
1247
+ name: "push",
1248
+ description: "Publish verified local commits to the remote branch without unsafe force pushes.",
1249
+ bodyLines: lines
1250
+ });
1251
+ }
1252
+
1253
+ // src/skills/templates/pull.ts
1254
+ function generatePullSkill(_ctx) {
1255
+ const lines = [];
1256
+ lines.push("# /pull \u2014 Git Pull / Sync Workflow");
1257
+ lines.push("");
1258
+ lines.push("## Trigger");
1259
+ lines.push("");
1440
1260
  lines.push(
1441
- `- \`${ctx.referenceWorkflowPath}\` may exist for compatibility with older generated ecosystems`
1261
+ "Use this skill to sync the current branch with the latest `origin/main`"
1442
1262
  );
1443
- lines.push("- `references/README.md` must exist beside this skill");
1444
- lines.push("- `gh` CLI must be authenticated");
1263
+ lines.push("before starting work or before creating a PR.");
1445
1264
  lines.push("");
1446
- lines.push("## Repository Validation Guidance");
1265
+ lines.push("## Flow");
1447
1266
  lines.push("");
1267
+ lines.push("1. Fetch latest from remote:");
1268
+ lines.push(" ```bash");
1269
+ lines.push(" git fetch origin");
1270
+ lines.push(" ```");
1271
+ lines.push("2. Merge into current branch:");
1272
+ lines.push(" ```bash");
1273
+ lines.push(" git merge origin/main");
1274
+ lines.push(" ```");
1275
+ lines.push("3. If conflicts arise:");
1276
+ lines.push(" - Resolve each conflict file");
1277
+ lines.push(" - Run tests to confirm nothing broke");
1448
1278
  lines.push(
1449
- "Carry the detected repository validation posture into any new or refined `WORKFLOW.md` instead of falling back to generic instructions."
1279
+ " - Commit the merge: `git commit` (merge commit message is auto-generated)"
1450
1280
  );
1451
- for (const line of buildRepositoryValidationGuidance(
1452
- ctx.detectedEnvironment
1453
- )) {
1454
- lines.push(`- ${line}`);
1455
- }
1281
+ lines.push(
1282
+ "4. Re-run tests after merge to confirm the integrated state is clean"
1283
+ );
1284
+ lines.push("5. Record pull skill evidence in workpad Notes:");
1285
+ lines.push(" - merge source (e.g. `origin/main`)");
1286
+ lines.push(" - result: `clean` or `conflicts resolved`");
1287
+ lines.push(" - resulting HEAD short SHA: `git rev-parse --short HEAD`");
1456
1288
  lines.push("");
1457
- lines.push("## Mode Detection");
1289
+ lines.push("## Rules");
1458
1290
  lines.push("");
1459
- lines.push("Check if `WORKFLOW.md` exists in the current directory:");
1460
- lines.push("- **Not found** \u2192 enter **Design Mode** (create from scratch)");
1461
- lines.push("- **Found** \u2192 ask user: refine existing or validate only?");
1462
- lines.push(" - Refine \u2192 enter **Refine Mode**");
1463
- lines.push(" - Validate \u2192 enter **Validate Mode**");
1291
+ lines.push("- Always pull before creating a PR");
1292
+ lines.push("- Always pull at the start of a new work session");
1293
+ lines.push("- Record the pull evidence in the workpad before proceeding");
1294
+ return renderSkillDocument({
1295
+ name: "pull",
1296
+ description: "Sync the current branch with the latest remote base before implementation or review handoff.",
1297
+ bodyLines: lines
1298
+ });
1299
+ }
1300
+
1301
+ // src/skills/templates/land.ts
1302
+ function generateLandSkill(_ctx) {
1303
+ const lines = [];
1304
+ lines.push("# /land \u2014 PR Merge Workflow");
1464
1305
  lines.push("");
1465
- lines.push("## Design Mode");
1306
+ lines.push("## Trigger");
1466
1307
  lines.push("");
1467
1308
  lines.push(
1468
- "1. Read `WORKFLOW.md` if it exists and extract repository conventions:"
1309
+ "Use this skill when the issue is in the Merging state (PR approved by human)."
1469
1310
  );
1470
- lines.push(" - test / lint / build commands from the prompt body");
1471
- lines.push(" - lifecycle states from front matter");
1472
1311
  lines.push(
1473
- "2. Read `references/README.md` for the available reference files."
1312
+ "Do NOT call `gh pr merge` directly \u2014 always go through this flow."
1474
1313
  );
1475
- lines.push('3. Ask the user: "What should this orchestration accomplish?"');
1476
- lines.push(" - implement (default) \u2014 write features / fix bugs");
1477
- lines.push(" - review \u2014 review PRs and leave comments");
1478
- lines.push(" - maintain \u2014 dependency bumps, chores, hygiene");
1479
- lines.push(" - custom \u2014 describe in their own words");
1314
+ lines.push("");
1315
+ lines.push("## Pre-flight Checks");
1316
+ lines.push("");
1317
+ lines.push("Before merging, verify ALL of the following:");
1318
+ lines.push("");
1319
+ lines.push("1. **PR is approved**:");
1320
+ lines.push(" ```bash");
1480
1321
  lines.push(
1481
- "4. Pick the matching `references/workflow-posture-*.md` file(s); compose multiple files when the intent spans categories."
1322
+ ` gh pr view --json reviews --jq '.reviews[] | select(.state == "APPROVED")'`
1482
1323
  );
1483
- lines.push("5. Ask these setup questions:");
1484
- lines.push(" - Which status columns should be **active** (agent works)?");
1485
- lines.push(" - Which should be **wait** (agent pauses for human)?");
1486
- lines.push(" - Which should be **terminal** (agent stops)?");
1487
- lines.push(" - What runtime is being used? (codex / claude-code / custom)");
1488
- lines.push(" - Any custom hooks needed? (after_create, before_run, etc.)");
1489
- lines.push("6. Generate WORKFLOW.md:");
1490
- lines.push(" - front matter from `references/workflow-schema.md`");
1324
+ lines.push(" ```");
1325
+ lines.push("2. **All CI checks are green**:");
1326
+ lines.push(" ```bash");
1327
+ lines.push(" gh pr checks");
1328
+ lines.push(" ```");
1329
+ lines.push("3. **Branch is up-to-date with base**:");
1330
+ lines.push(" ```bash");
1491
1331
  lines.push(
1492
- " - prompt body from the selected posture file(s), adapted to actual repository commands"
1332
+ " git fetch origin && git merge-base --is-ancestor origin/main HEAD"
1493
1333
  );
1494
- lines.push("7. Show a diff or preview and confirm with the user.");
1495
- lines.push("8. Validate via `gh-symphony workflow validate`.");
1334
+ lines.push(" ```");
1335
+ lines.push(" If not up-to-date, run the `/pull` skill first.");
1496
1336
  lines.push("");
1497
- lines.push("## Refine Mode");
1337
+ lines.push("## Flow");
1498
1338
  lines.push("");
1499
- lines.push("1. Read the current `WORKFLOW.md`");
1500
- lines.push(
1501
- "2. Read `references/README.md` and select the relevant posture file(s)"
1502
- );
1339
+ lines.push("1. Run all pre-flight checks above");
1340
+ lines.push("2. If all checks pass, merge the PR:");
1341
+ lines.push(" ```bash");
1342
+ lines.push(" gh pr merge --squash # squash merge (default)");
1343
+ lines.push(" # or: gh pr merge --merge # merge commit");
1344
+ lines.push(" # or: gh pr merge --rebase # rebase merge");
1345
+ lines.push(" ```");
1346
+ lines.push(" Choose the merge strategy per project policy.");
1347
+ lines.push("3. On merge success:");
1503
1348
  lines.push(
1504
- "3. Compare the current prompt body against the selected posture references"
1349
+ " - Use the **gh-project skill** to transition the issue status to Done"
1505
1350
  );
1506
- lines.push("4. Identify missing or incomplete sections:");
1507
- lines.push(" - Status Map with role annotations");
1508
- lines.push(" - Default Posture / Agent Instructions");
1509
- lines.push(" - Guardrails section");
1510
- lines.push(" - Workpad Template");
1511
- lines.push(" - Step 0 routing logic");
1512
- lines.push("5. Propose improvements and apply with user confirmation");
1513
- lines.push("6. Validate the refined file");
1351
+ lines.push(" - Do NOT call status APIs directly \u2014 delegate to gh-project");
1352
+ lines.push("4. On merge failure:");
1353
+ lines.push(" - Record the failure reason in workpad Notes");
1354
+ lines.push(" - Resolve the blocking issue (re-run pre-flight checks)");
1355
+ lines.push(" - Retry the merge");
1356
+ lines.push("5. Loop until merged or blocked by an unresolvable issue");
1514
1357
  lines.push("");
1515
- lines.push("## Validate Mode");
1358
+ lines.push("## Rules");
1516
1359
  lines.push("");
1517
- lines.push("Check the WORKFLOW.md for:");
1518
- lines.push("- Front matter is valid YAML");
1360
+ lines.push("- Never call `gh pr merge` without completing pre-flight checks");
1519
1361
  lines.push(
1520
- "- Required fields are present (see `references/workflow-schema.md`)"
1362
+ "- Status transition to Done MUST go through the gh-project skill"
1521
1363
  );
1522
1364
  lines.push(
1523
- "- Template variables use only supported names (see `references/workflow-schema.md`)"
1365
+ "- If any pre-flight check fails, do not merge \u2014 fix the issue first"
1524
1366
  );
1525
- lines.push("- Status Map matches the lifecycle configuration");
1367
+ lines.push("- Record all merge attempts and outcomes in the workpad");
1368
+ return renderSkillDocument({
1369
+ name: "land",
1370
+ description: "Merge approved pull requests safely after verifying approvals, CI, and branch freshness.",
1371
+ bodyLines: lines
1372
+ });
1373
+ }
1374
+
1375
+ // src/skills/templates/gh-symphony-references/readme.ts
1376
+ function generateGhSymphonyReferencesReadme(_ctx) {
1377
+ return [
1378
+ "# /gh-symphony references",
1379
+ "",
1380
+ "The /gh-symphony skill consults these files when designing or refining",
1381
+ "WORKFLOW.md.",
1382
+ "",
1383
+ "## Schema",
1384
+ "",
1385
+ "| File | What it is |",
1386
+ "| ---- | ---------- |",
1387
+ "| `workflow-schema.md` | All supported front matter fields and their types. |",
1388
+ "",
1389
+ "## Workflow prompt body postures",
1390
+ "",
1391
+ "When the user describes what the orchestration should do, pick the matching",
1392
+ "posture file(s) and use its prompt-body sections as the seed. Postures can be",
1393
+ "combined when the user's intent spans multiple categories.",
1394
+ "",
1395
+ "| File | Use when the user wants... |",
1396
+ "| ---- | -------------------------- |",
1397
+ "| `workflow-posture-implement.md` | Coding agent writes features / bug fixes (default). |",
1398
+ "| `workflow-posture-review.md` | Agent reviews PRs and leaves comments. No code writes. |",
1399
+ "| `workflow-posture-maintain.md` | Minimal-change maintenance: deps, lint sweeps, hygiene. |",
1400
+ "",
1401
+ "## Adding your own reference",
1402
+ "",
1403
+ "Drop a markdown file here with a descriptive name. The skill discovers files",
1404
+ "on each invocation; no code changes needed."
1405
+ ].join("\n");
1406
+ }
1407
+
1408
+ // src/workflow/generate-reference-workflow.ts
1409
+ function generateReferenceWorkflow(input) {
1410
+ const lines = [];
1411
+ lines.push("# Reference WORKFLOW.md \u2014 gh-symphony");
1412
+ lines.push("# This file is a reference template for authoring WORKFLOW.md.");
1526
1413
  lines.push(
1527
- "- No unsupported double-brace variable patterns (only the 8 listed below are valid)"
1414
+ "# AI agents reference this file (via the /gh-symphony skill) when designing WORKFLOW.md."
1528
1415
  );
1416
+ lines.push("# Do not edit this file directly.");
1417
+ lines.push("");
1418
+ lines.push("---");
1419
+ lines.push("");
1420
+ lines.push("# \u2550\u2550\u2550 FRONT MATTER FIELD REFERENCE \u2550\u2550\u2550");
1529
1421
  lines.push(
1530
- "- Prompt body posture is consistent with the selected `references/workflow-posture-*.md` file(s)"
1422
+ "# All front matter fields supported by the gh-symphony parser are listed below."
1531
1423
  );
1532
1424
  lines.push("");
1533
- lines.push("## Supported Front Matter Fields");
1534
- lines.push("");
1535
- lines.push("```yaml");
1536
1425
  lines.push("tracker:");
1537
1426
  lines.push(" kind: github-project");
1538
- lines.push(" project_id: PVT_xxx");
1427
+ lines.push(` project_id: ${input.projectId}`);
1539
1428
  lines.push(" state_field: Status");
1540
- lines.push(" active_states: [Todo, In Progress]");
1541
- lines.push(" terminal_states: [Done, Cancelled]");
1542
- lines.push(" blocker_check_states: [Blocked]");
1429
+ lines.push(...buildReferencePriorityLines(input.priority));
1430
+ lines.push("");
1431
+ const activeColumns = input.statusColumns.filter((c) => c.role === "active");
1432
+ const waitColumns = input.statusColumns.filter((c) => c.role === "wait");
1433
+ const terminalColumns = input.statusColumns.filter(
1434
+ (c) => c.role === "terminal"
1435
+ );
1436
+ const blockerCheckStates = input.lifecycle?.blockerCheckStates ?? [];
1437
+ const planningStates = input.lifecycle?.planningStates ?? blockerCheckStates;
1438
+ if (activeColumns.length > 0) {
1439
+ lines.push(" active_states:");
1440
+ for (const col of activeColumns) {
1441
+ lines.push(` - ${col.name}`);
1442
+ }
1443
+ } else {
1444
+ lines.push(" active_states: [{active column names}]");
1445
+ }
1446
+ if (terminalColumns.length > 0) {
1447
+ lines.push(" terminal_states:");
1448
+ for (const col of terminalColumns) {
1449
+ lines.push(` - ${col.name}`);
1450
+ }
1451
+ } else {
1452
+ lines.push(" terminal_states: [{terminal column names}]");
1453
+ }
1454
+ lines.push(
1455
+ ...buildReferenceStringList("blocker_check_states", blockerCheckStates)
1456
+ );
1457
+ lines.push(...buildReferenceStringList("planning_states", planningStates));
1458
+ lines.push("");
1459
+ lines.push("# Linear tracker example:");
1460
+ lines.push("# tracker:");
1461
+ lines.push("# kind: linear");
1462
+ lines.push("# endpoint: https://api.linear.app/graphql");
1463
+ lines.push("# api_key: $LINEAR_API_KEY");
1464
+ lines.push("# project_slug: symphony-0c79b11b75ea");
1465
+ lines.push("# active_states:");
1466
+ lines.push("# - Todo");
1467
+ lines.push("# - In Progress");
1468
+ lines.push("# terminal_states:");
1469
+ lines.push("# - Done");
1470
+ lines.push("# - Canceled");
1471
+ lines.push("# - Duplicate");
1472
+ lines.push(
1473
+ "# Linear uses repository-local polling; gh-symphony does not provide"
1474
+ );
1475
+ lines.push("# a Linear webhook setup command.");
1476
+ lines.push("");
1543
1477
  lines.push("polling:");
1544
1478
  lines.push(" interval_ms: 30000");
1479
+ lines.push("");
1545
1480
  lines.push("workspace:");
1546
1481
  lines.push(" root: .runtime/symphony-workspaces");
1482
+ lines.push("");
1547
1483
  lines.push("hooks:");
1548
- lines.push(" after_create: |");
1549
- lines.push(" git clone --depth 1 https://github.com/owner/repo .");
1484
+ lines.push(
1485
+ ` after_create: ${DEFAULT_AFTER_CREATE_HOOK_PATH} # ${DEFAULT_AFTER_CREATE_HOOK_COMMENT}`
1486
+ );
1550
1487
  lines.push(" before_run: null");
1551
1488
  lines.push(" after_run: null");
1552
1489
  lines.push(" before_remove: null");
1553
1490
  lines.push(" timeout_ms: 60000");
1491
+ lines.push("");
1554
1492
  lines.push("agent:");
1555
1493
  lines.push(" max_concurrent_agents: 10");
1556
1494
  lines.push(" max_retry_backoff_ms: 30000");
1557
1495
  lines.push(" retry_base_delay_ms: 10000");
1558
1496
  lines.push(" max_turns: 20");
1559
- lines.push("codex:");
1560
- lines.push(" command: codex app-server");
1561
- lines.push(" read_timeout_ms: 5000");
1562
- lines.push(" turn_timeout_ms: 3600000");
1563
- lines.push(" stall_timeout_ms: 300000");
1564
- lines.push("```");
1565
- lines.push("");
1566
- lines.push("## Supported Template Variables");
1567
1497
  lines.push("");
1568
- lines.push("Use these in the WORKFLOW.md prompt body (double-brace syntax):");
1498
+ lines.push(...buildRuntimeFrontMatter(input.runtime));
1569
1499
  lines.push("");
1570
- lines.push("| Variable | Description |");
1571
- lines.push("|----------|-------------|");
1572
- lines.push("| `issue.identifier` | e.g. `acme/platform#42` |");
1573
- lines.push("| `issue.title` | Issue title |");
1574
- lines.push("| `issue.state` | Current tracker state |");
1575
- lines.push("| `issue.description` | Issue body |");
1576
- lines.push("| `issue.url` | Issue URL |");
1577
- lines.push("| `issue.repository` | `owner/name` |");
1578
- lines.push("| `issue.number` | Issue number |");
1579
- lines.push("| `attempt` | Retry attempt number (null on first run) |");
1500
+ lines.push("---");
1580
1501
  lines.push("");
1502
+ lines.push("# \u2550\u2550\u2550 PROMPT BODY REFERENCE \u2550\u2550\u2550");
1581
1503
  lines.push(
1582
- "**Important**: Only these 8 variables are supported. Using any other variable"
1504
+ "# GitHub Project adaptation of the Elixir Symphony reference prompt."
1583
1505
  );
1584
- lines.push("will cause a runtime error (strict mode validation).");
1585
1506
  lines.push("");
1586
- lines.push("## Related Skills");
1507
+ lines.push("## Status Map");
1508
+ lines.push("");
1509
+ lines.push("| Status | Role | Agent Action |");
1510
+ lines.push("| ------ | ---- | ------------ |");
1511
+ for (const col of input.statusColumns) {
1512
+ const roleLabel = col.role ?? "unset";
1513
+ const action = resolveRoleAction(col.role);
1514
+ lines.push(`| ${col.name} | ${roleLabel} | ${action} |`);
1515
+ }
1516
+ if (waitColumns.length > 0) {
1517
+ lines.push("");
1518
+ lines.push("**Wait States (awaiting PR review):**");
1519
+ for (const col of waitColumns) {
1520
+ lines.push(
1521
+ `- **${col.name}**: PR created. Awaiting human review. Agent is idle.`
1522
+ );
1523
+ }
1524
+ }
1525
+ lines.push("");
1526
+ lines.push("## Repository Validation Guidance");
1527
+ lines.push("");
1528
+ for (const line of buildRepositoryValidationGuidance(
1529
+ input.detectedEnvironment
1530
+ )) {
1531
+ lines.push(`- ${line}`);
1532
+ }
1533
+ lines.push("");
1534
+ lines.push("## Default Posture");
1587
1535
  lines.push("");
1588
1536
  lines.push(
1589
- "- `/gh-project` \u2014 interact with GitHub Project v2 board (status transitions, workpad comments)"
1537
+ "1. This is an unattended orchestration session. Do not ask humans for follow-up tasks."
1590
1538
  );
1591
1539
  lines.push(
1592
- "- `/commit` \u2014 produce clean, logical commits during implementation"
1540
+ "2. Exit early only for genuine blockers (missing required credentials or secrets)."
1593
1541
  );
1594
- lines.push("- `/push` \u2014 keep remote branch current and publish updates");
1595
- lines.push("- `/pull` \u2014 sync branch with latest origin/main before handoff");
1596
- lines.push("- `/land` \u2014 merge approved PR and transition issue to Done");
1597
- return renderSkillDocument({
1598
- name: "gh-symphony",
1599
- description: "Design, refine, and validate repository WORKFLOW.md files for GitHub Symphony projects.",
1600
- bodyLines: lines
1601
- });
1602
- }
1603
-
1604
- // src/skills/templates/gh-project.ts
1605
- function generateGhProjectSkill(ctx) {
1606
- const lines = [];
1607
- lines.push("# /gh-project \u2014 GitHub Project v2 Status Management");
1608
- lines.push("");
1609
- lines.push("## Purpose");
1610
- lines.push("");
1611
1542
  lines.push(
1612
- "Interact with the GitHub Project v2 board to manage issue status,"
1543
+ '3. In your final message, report only completed work and blockers. Do not include "next steps".'
1544
+ );
1545
+ lines.push(
1546
+ "4. Do not modify the issue body for planning or progress-tracking purposes."
1547
+ );
1548
+ lines.push(
1549
+ "5. If the issue is in a terminal state, do nothing and exit immediately."
1613
1550
  );
1614
- lines.push("create workpad comments, and handle follow-up issues.");
1615
- lines.push("");
1616
- lines.push("## Prerequisites");
1617
- lines.push("");
1618
- lines.push("- `gh` CLI is authenticated (`gh auth status`)");
1619
1551
  lines.push(
1620
- `- \`${ctx.contextYamlPath}\` exists with field IDs and option IDs`
1552
+ "6. If you discover out-of-scope improvements, open a separate issue rather than expanding the current scope."
1621
1553
  );
1622
- lines.push("");
1623
- lines.push("## Column ID Quick Reference");
1624
- lines.push("");
1625
- lines.push(`Status Field ID: \`${ctx.statusFieldId}\``);
1626
- lines.push("");
1627
- lines.push("| Column Name | Role | Option ID |");
1628
- lines.push("|-------------|------|-----------|");
1629
- for (const col of ctx.statusColumns) {
1630
- const role = col.role ?? "unknown";
1631
- lines.push(`| ${col.name} | ${role} | \`${col.id}\` |`);
1632
- }
1633
- lines.push("");
1634
- lines.push("## Operations");
1635
- lines.push("");
1636
- lines.push("### Change Issue Status");
1637
- lines.push("");
1638
1554
  lines.push(
1639
- "Use `gh project item-edit` with the field ID and option ID from the table above:"
1555
+ "7. Keep all commits as logical units and follow conventional commit format."
1640
1556
  );
1641
- lines.push("");
1642
- lines.push("```bash");
1643
- lines.push("# Get the project item ID for an issue");
1557
+ lines.push("8. Do not make commits that break existing tests.");
1558
+ lines.push("9. Verify all existing tests pass before creating a PR.");
1559
+ lines.push("10. Create a workpad as an issue comment to track progress.");
1560
+ lines.push("11. Use the gh-project skill to manage issue status.");
1644
1561
  lines.push(
1645
- "gh project item-list <project-number> --owner <owner> --format json \\"
1562
+ "12. When a blocker is found, record it in an issue comment and transition the status appropriately."
1646
1563
  );
1647
1564
  lines.push(
1648
- " | jq '.items[] | select(.content.number == <issue-number>) | .id'"
1565
+ "13. Once your work is complete and the PR is merged, transition the issue to the Done state."
1649
1566
  );
1650
1567
  lines.push("");
1651
- lines.push("# Update the status field");
1652
- lines.push(`gh project item-edit \\`);
1653
- lines.push(` --project-id ${ctx.projectId} \\`);
1654
- lines.push(` --id <item-id> \\`);
1655
- lines.push(` --field-id ${ctx.statusFieldId} \\`);
1656
- lines.push(` --single-select-option-id <option-id-from-table-above>`);
1657
- lines.push("```");
1658
- lines.push("");
1659
- lines.push("### Create Workpad Comment");
1568
+ lines.push("## Related Skills");
1660
1569
  lines.push("");
1661
- lines.push("```bash");
1662
1570
  lines.push(
1663
- 'gh issue comment <issue-number> --repo <owner>/<repo> --body "## Workpad\\n\\n### Plan\\n- [ ] Task 1"'
1571
+ "- **gh-project**: Manage GitHub Project v2 issue status and update fields"
1664
1572
  );
1665
- lines.push("```");
1666
- lines.push("");
1667
- lines.push("### Update Existing Comment");
1668
- lines.push("");
1669
- lines.push("```bash");
1670
1573
  lines.push(
1671
- "gh api -X PATCH /repos/<owner>/<repo>/issues/comments/<comment-id> \\"
1574
+ "- **commit**: Create logical-unit commits (conventional commit format)"
1672
1575
  );
1673
- lines.push(' -f body="## Workpad\\n\\n### Plan\\n- [x] Task 1 (done)"');
1674
- lines.push("```");
1675
- lines.push("");
1676
- lines.push("### Create Follow-up Issue");
1576
+ lines.push("- **push**: Push branch and sync with the remote repository");
1577
+ lines.push("- **pull**: Fetch latest changes and resolve conflicts");
1578
+ lines.push("- **land**: Create PR, request review, and handle merge");
1677
1579
  lines.push("");
1678
- lines.push("```bash");
1679
- lines.push("gh issue create --repo <owner>/<repo> \\");
1680
- lines.push(' --title "Follow-up: <title>" \\');
1681
- lines.push(' --body "<description>" \\');
1682
- lines.push(' --label "backlog"');
1683
- lines.push("```");
1580
+ lines.push("## Step 0: Determine current state and route");
1684
1581
  lines.push("");
1685
- lines.push("### Add Label");
1582
+ lines.push(
1583
+ "Check the current issue state and route to the appropriate step:"
1584
+ );
1686
1585
  lines.push("");
1687
- lines.push("```bash");
1586
+ if (terminalColumns.length > 0) {
1587
+ const terminalNames = terminalColumns.map((c) => c.name).join(", ");
1588
+ lines.push(`- **${terminalNames}** \u2192 Exit immediately. Do nothing.`);
1589
+ }
1590
+ if (waitColumns.length > 0) {
1591
+ const waitNames = waitColumns.map((c) => c.name).join(", ");
1592
+ lines.push(`- **${waitNames}** \u2192 Go to Step 3 (handle awaiting review).`);
1593
+ }
1594
+ if (activeColumns.length > 0) {
1595
+ const activeNames = activeColumns.map((c) => c.name).join(", ");
1596
+ lines.push(
1597
+ `- **${activeNames}** \u2192 Go to Step 1 (start or continue execution).`
1598
+ );
1599
+ }
1688
1600
  lines.push(
1689
- 'gh issue edit <issue-number> --repo <owner>/<repo> --add-label "<label>"'
1601
+ "- **Other states** \u2192 Log the unclear state in an issue comment and exit."
1690
1602
  );
1691
- lines.push("```");
1692
1603
  lines.push("");
1693
- lines.push("## Rules");
1604
+ lines.push("## Step 1: Start/continue execution");
1694
1605
  lines.push("");
1695
1606
  lines.push(
1696
- "- Always follow the WORKFLOW.md status map flow for state transitions"
1607
+ "1. Read the issue body and comments to understand current progress."
1697
1608
  );
1698
1609
  lines.push(
1699
- "- Before transitioning to a terminal state, verify the Completion Bar is satisfied:"
1610
+ "2. If an existing workpad comment is found, continue from it; otherwise create a new workpad."
1700
1611
  );
1701
- lines.push(" - All acceptance criteria checked");
1702
- lines.push(" - All tests passing");
1703
- lines.push(" - PR merged (if applicable)");
1704
1612
  lines.push(
1705
- "- Use the Column ID Quick Reference table above for all status transitions"
1613
+ "3. See the 'Workpad Template' section below for the workpad format."
1706
1614
  );
1707
1615
  lines.push(
1708
- "- Do not transition issues to terminal states without explicit completion verification"
1616
+ "4. If no branch exists, create a feature branch based on `{issue.repository}`."
1709
1617
  );
1710
- return renderSkillDocument({
1711
- name: "gh-project",
1712
- description: "Manage GitHub Project v2 issue states, workpad comments, and related follow-up actions.",
1713
- bodyLines: lines
1714
- });
1715
- }
1716
-
1717
- // src/skills/templates/commit.ts
1718
- function generateCommitSkill(_ctx) {
1719
- const lines = [];
1720
- lines.push("# /commit \u2014 Clean Commit Workflow");
1721
- lines.push("");
1722
- lines.push("## Trigger");
1723
- lines.push("");
1724
- lines.push("Use this skill when creating commits during implementation.");
1725
- lines.push("");
1726
- lines.push("## Rules");
1727
- lines.push("");
1728
- lines.push("- Commit in logical units \u2014 one concern per commit");
1729
- lines.push("- Never commit a broken intermediate state (tests must pass)");
1730
- lines.push("- Never commit temporary debug code or commented-out blocks");
1731
- lines.push("- Run tests before every commit");
1732
- lines.push("");
1733
- lines.push("## Format");
1734
- lines.push("");
1735
- lines.push("Use Conventional Commit format:");
1736
- lines.push("");
1737
- lines.push("```");
1738
- lines.push("<type>(<scope>): <description>");
1739
- lines.push("");
1740
- lines.push("[optional body \u2014 explain WHY, not WHAT, 72 chars/line]");
1741
- lines.push("");
1742
- lines.push("[optional footer: Closes #N]");
1743
- lines.push("```");
1618
+ lines.push("5. Proceed to Step 2.");
1744
1619
  lines.push("");
1745
- lines.push("**Types**: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`");
1620
+ lines.push("## Step 2: Execution phase");
1746
1621
  lines.push("");
1622
+ lines.push("1. Implement according to the issue description.");
1747
1623
  lines.push(
1748
- "**Description**: imperative mood, 50 chars max, no period at end"
1624
+ "2. Commit changes in logical units (conventional commit format)."
1749
1625
  );
1750
- lines.push("");
1751
- lines.push("## Examples");
1752
- lines.push("");
1753
- lines.push("```");
1754
- lines.push("feat(auth): add OAuth2 token refresh");
1755
- lines.push("fix(api): handle null response from upstream");
1756
- lines.push("test(worker): add retry exhaustion coverage");
1757
- lines.push("```");
1758
- return renderSkillDocument({
1759
- name: "commit",
1760
- description: "Create clean, logically scoped commits that keep the repository in a shippable state.",
1761
- bodyLines: lines
1762
- });
1763
- }
1764
-
1765
- // src/skills/templates/push.ts
1766
- function generatePushSkill(_ctx) {
1767
- const lines = [];
1768
- lines.push("# /push \u2014 Git Push Workflow");
1769
- lines.push("");
1770
- lines.push("## Trigger");
1771
- lines.push("");
1626
+ lines.push("3. Verify all existing tests pass.");
1627
+ lines.push("4. Write tests for new functionality.");
1628
+ lines.push("5. Once all Completion Bar criteria are met, create a PR.");
1772
1629
  lines.push(
1773
- "Use this skill when publishing local commits to the remote branch."
1630
+ "6. After creating the PR, transition the issue status to the Human Review state."
1774
1631
  );
1632
+ lines.push("7. Proceed to Step 3.");
1775
1633
  lines.push("");
1776
- lines.push("## Flow");
1777
- lines.push("");
1778
- lines.push("1. Run local tests and lint \u2014 ensure they pass before pushing");
1779
- lines.push("2. Push to remote:");
1780
- lines.push(" ```bash");
1781
- lines.push(" git push origin <branch> # subsequent pushes");
1782
- lines.push(" git push -u origin <branch> # first push (sets upstream)");
1783
- lines.push(" ```");
1784
- lines.push("3. If push is rejected (non-fast-forward):");
1785
- lines.push(" - Run `git fetch origin && git merge origin/main`");
1786
- lines.push(" - Resolve any conflicts");
1787
- lines.push(" - Re-run tests");
1788
- lines.push(" - Push again");
1789
- lines.push("4. Record push result in workpad Notes");
1790
- lines.push("");
1791
- lines.push("## Rules");
1634
+ lines.push("## Step 3: Human Review and merge handling");
1792
1635
  lines.push("");
1793
- lines.push("- Never use `--force` (destructive)");
1636
+ lines.push("1. If a PR already exists, check for review comments.");
1794
1637
  lines.push(
1795
- "- Only use `--force-with-lease` if absolutely necessary \u2014 record the reason in workpad"
1638
+ "2. If no review comments are present, remain in the waiting state."
1796
1639
  );
1797
- lines.push("- Verify CI starts after push (check GitHub Actions tab)");
1798
- lines.push("- Do not push directly to `main` or `master`");
1799
- return renderSkillDocument({
1800
- name: "push",
1801
- description: "Publish verified local commits to the remote branch without unsafe force pushes.",
1802
- bodyLines: lines
1803
- });
1804
- }
1805
-
1806
- // src/skills/templates/pull.ts
1807
- function generatePullSkill(_ctx) {
1808
- const lines = [];
1809
- lines.push("# /pull \u2014 Git Pull / Sync Workflow");
1810
- lines.push("");
1811
- lines.push("## Trigger");
1812
- lines.push("");
1813
1640
  lines.push(
1814
- "Use this skill to sync the current branch with the latest `origin/main`"
1641
+ "3. If the PR is merged, transition the issue to a terminal state."
1815
1642
  );
1816
- lines.push("before starting work or before creating a PR.");
1643
+ lines.push("4. If review changes are requested, proceed to Step 4.");
1817
1644
  lines.push("");
1818
- lines.push("## Flow");
1645
+ lines.push("## Step 4: Rework handling");
1819
1646
  lines.push("");
1820
- lines.push("1. Fetch latest from remote:");
1821
- lines.push(" ```bash");
1822
- lines.push(" git fetch origin");
1823
- lines.push(" ```");
1824
- lines.push("2. Merge into current branch:");
1825
- lines.push(" ```bash");
1826
- lines.push(" git merge origin/main");
1827
- lines.push(" ```");
1828
- lines.push("3. If conflicts arise:");
1829
- lines.push(" - Resolve each conflict file");
1830
- lines.push(" - Run tests to confirm nothing broke");
1831
1647
  lines.push(
1832
- " - Commit the merge: `git commit` (merge commit message is auto-generated)"
1648
+ "1. Read all PR review comments and identify the requested changes."
1833
1649
  );
1834
1650
  lines.push(
1835
- "4. Re-run tests after merge to confirm the integrated state is clean"
1651
+ "2. Process the changes following the PR Feedback Sweep Protocol."
1836
1652
  );
1837
- lines.push("5. Record pull skill evidence in workpad Notes:");
1838
- lines.push(" - merge source (e.g. `origin/main`)");
1839
- lines.push(" - result: `clean` or `conflicts resolved`");
1840
- lines.push(" - resulting HEAD short SHA: `git rev-parse --short HEAD`");
1841
- lines.push("");
1842
- lines.push("## Rules");
1653
+ lines.push("3. After implementing changes, commit and update the PR.");
1654
+ lines.push("4. Transition the issue status back to the Human Review state.");
1655
+ lines.push("5. Return to Step 3.");
1843
1656
  lines.push("");
1844
- lines.push("- Always pull before creating a PR");
1845
- lines.push("- Always pull at the start of a new work session");
1846
- lines.push("- Record the pull evidence in the workpad before proceeding");
1847
- return renderSkillDocument({
1848
- name: "pull",
1849
- description: "Sync the current branch with the latest remote base before implementation or review handoff.",
1850
- bodyLines: lines
1851
- });
1852
- }
1853
-
1854
- // src/skills/templates/land.ts
1855
- function generateLandSkill(_ctx) {
1856
- const lines = [];
1857
- lines.push("# /land \u2014 PR Merge Workflow");
1657
+ lines.push("## PR Feedback Sweep Protocol");
1858
1658
  lines.push("");
1859
- lines.push("## Trigger");
1659
+ lines.push("Order for processing PR review feedback:");
1860
1660
  lines.push("");
1861
1661
  lines.push(
1862
- "Use this skill when the issue is in the Merging state (PR approved by human)."
1662
+ "1. **Collect all comments**: List all unresolved review comments."
1663
+ );
1664
+ lines.push(
1665
+ "2. **Triage by priority**: Handle blocking comments before non-blocking ones."
1863
1666
  );
1864
1667
  lines.push(
1865
- "Do NOT call `gh pr merge` directly \u2014 always go through this flow."
1668
+ "3. **Implement changes**: Make the code changes corresponding to each comment."
1866
1669
  );
1867
- lines.push("");
1868
- lines.push("## Pre-flight Checks");
1869
- lines.push("");
1870
- lines.push("Before merging, verify ALL of the following:");
1871
- lines.push("");
1872
- lines.push("1. **PR is approved**:");
1873
- lines.push(" ```bash");
1874
1670
  lines.push(
1875
- ` gh pr view --json reviews --jq '.reviews[] | select(.state == "APPROVED")'`
1671
+ "4. **Reply to comments**: Respond to each review comment with a description of what was done."
1876
1672
  );
1877
- lines.push(" ```");
1878
- lines.push("2. **All CI checks are green**:");
1879
- lines.push(" ```bash");
1880
- lines.push(" gh pr checks");
1881
- lines.push(" ```");
1882
- lines.push("3. **Branch is up-to-date with base**:");
1883
- lines.push(" ```bash");
1884
1673
  lines.push(
1885
- " git fetch origin && git merge-base --is-ancestor origin/main HEAD"
1674
+ "5. **Commit**: Commit changes in `fix: address PR review feedback` format."
1886
1675
  );
1887
- lines.push(" ```");
1888
- lines.push(" If not up-to-date, run the `/pull` skill first.");
1676
+ lines.push("6. **Request re-review**: Ask the reviewer for a re-review.");
1889
1677
  lines.push("");
1890
- lines.push("## Flow");
1678
+ lines.push("## Completion Bar");
1679
+ lines.push("");
1680
+ lines.push("All of the following must be satisfied before creating a PR:");
1891
1681
  lines.push("");
1892
- lines.push("1. Run all pre-flight checks above");
1893
- lines.push("2. If all checks pass, merge the PR:");
1894
- lines.push(" ```bash");
1895
- lines.push(" gh pr merge --squash # squash merge (default)");
1896
- lines.push(" # or: gh pr merge --merge # merge commit");
1897
- lines.push(" # or: gh pr merge --rebase # rebase merge");
1898
- lines.push(" ```");
1899
- lines.push(" Choose the merge strategy per project policy.");
1900
- lines.push("3. On merge success:");
1901
1682
  lines.push(
1902
- " - Use the **gh-project skill** to transition the issue status to Done"
1683
+ "- [ ] All requirements from the issue description are implemented."
1903
1684
  );
1904
- lines.push(" - Do NOT call status APIs directly \u2014 delegate to gh-project");
1905
- lines.push("4. On merge failure:");
1906
- lines.push(" - Record the failure reason in workpad Notes");
1907
- lines.push(" - Resolve the blocking issue (re-run pre-flight checks)");
1908
- lines.push(" - Retry the merge");
1909
- lines.push("5. Loop until merged or blocked by an unresolvable issue");
1685
+ lines.push("- [ ] All existing tests pass.");
1686
+ lines.push("- [ ] Tests are written for new functionality.");
1687
+ lines.push("- [ ] Code style follows project conventions.");
1688
+ lines.push("- [ ] The PR description clearly explains the changes.");
1689
+ lines.push("- [ ] Related documentation is updated (if applicable).");
1910
1690
  lines.push("");
1911
- lines.push("## Rules");
1691
+ lines.push("## Guardrails");
1912
1692
  lines.push("");
1913
- lines.push("- Never call `gh pr merge` without completing pre-flight checks");
1693
+ lines.push("- **Scope**: Never make changes outside the scope of the issue.");
1914
1694
  lines.push(
1915
- "- Status transition to Done MUST go through the gh-project skill"
1695
+ "- **Secrets**: Never hardcode tokens, passwords, or API keys in code."
1916
1696
  );
1917
1697
  lines.push(
1918
- "- If any pre-flight check fails, do not merge \u2014 fix the issue first"
1698
+ "- **Breaking changes**: Do not modify existing APIs or interfaces without explicit authorization."
1919
1699
  );
1920
- lines.push("- Record all merge attempts and outcomes in the workpad");
1921
- return renderSkillDocument({
1922
- name: "land",
1923
- description: "Merge approved pull requests safely after verifying approvals, CI, and branch freshness.",
1924
- bodyLines: lines
1925
- });
1700
+ lines.push("- **Force push**: Do not force-push to the main/master branch.");
1701
+ lines.push(
1702
+ "- **Issue body**: Do not modify the issue body for progress tracking."
1703
+ );
1704
+ lines.push(
1705
+ "- **Infinite loops**: If the same task fails 3 or more consecutive times, log it as a blocker and exit."
1706
+ );
1707
+ lines.push("");
1708
+ lines.push("## Workpad Template");
1709
+ lines.push("");
1710
+ lines.push("Workpad format to create as an issue comment:");
1711
+ lines.push("");
1712
+ lines.push("```markdown");
1713
+ lines.push("## Workpad \u2014 {issue.identifier}");
1714
+ lines.push("");
1715
+ lines.push("**Status**: {current phase}");
1716
+ lines.push("**Branch**: {branch name}");
1717
+ lines.push("**PR**: {PR URL or not created}");
1718
+ lines.push("");
1719
+ lines.push("### Plan");
1720
+ lines.push("");
1721
+ lines.push("- [ ] {task 1}");
1722
+ lines.push("- [ ] {task 2}");
1723
+ lines.push("");
1724
+ lines.push("### Progress Log");
1725
+ lines.push("");
1726
+ lines.push("- {timestamp}: {action taken}");
1727
+ lines.push("");
1728
+ lines.push("### Blockers");
1729
+ lines.push("");
1730
+ lines.push("None");
1731
+ lines.push("```");
1732
+ lines.push("");
1733
+ return lines.join("\n");
1926
1734
  }
1927
-
1928
- // src/skills/templates/gh-symphony-references/readme.ts
1929
- function generateGhSymphonyReferencesReadme(_ctx) {
1930
- return [
1931
- "# /gh-symphony references",
1932
- "",
1933
- "The /gh-symphony skill consults these files when designing or refining",
1934
- "WORKFLOW.md.",
1935
- "",
1936
- "## Schema",
1937
- "",
1938
- "| File | What it is |",
1939
- "| ---- | ---------- |",
1940
- "| `workflow-schema.md` | All supported front matter fields and their types. |",
1941
- "",
1942
- "## Workflow prompt body postures",
1943
- "",
1944
- "When the user describes what the orchestration should do, pick the matching",
1945
- "posture file(s) and use its prompt-body sections as the seed. Postures can be",
1946
- "combined when the user's intent spans multiple categories.",
1947
- "",
1948
- "| File | Use when the user wants... |",
1949
- "| ---- | -------------------------- |",
1950
- "| `workflow-posture-implement.md` | Coding agent writes features / bug fixes (default). |",
1951
- "| `workflow-posture-review.md` | Agent reviews PRs and leaves comments. No code writes. |",
1952
- "| `workflow-posture-maintain.md` | Minimal-change maintenance: deps, lint sweeps, hygiene. |",
1953
- "",
1954
- "## Adding your own reference",
1955
- "",
1956
- "Drop a markdown file here with a descriptive name. The skill discovers files",
1957
- "on each invocation; no code changes needed."
1958
- ].join("\n");
1735
+ function buildReferenceStringList(key, values) {
1736
+ if (values.length === 0) {
1737
+ return [` ${key}: []`];
1738
+ }
1739
+ return [` ${key}:`, ...values.map((value) => ` - ${value}`)];
1740
+ }
1741
+ function buildReferencePriorityLines(priority) {
1742
+ const lines = [];
1743
+ if (priority?.source === "project-field" || priority?.source === "labels") {
1744
+ lines.push(
1745
+ " # Priority is explicit. Numbers below are editable policy (lower = higher priority)."
1746
+ );
1747
+ } else {
1748
+ lines.push(
1749
+ " # Priority dispatch is disabled until an operator chooses one explicit source."
1750
+ );
1751
+ }
1752
+ lines.push(
1753
+ " # See docs/adr/2026-05-18_explicit-dispatch-priority-mappings.md"
1754
+ );
1755
+ if (priority?.source === "project-field") {
1756
+ lines.push(" priority:");
1757
+ lines.push(" source: project-field");
1758
+ lines.push(` field: ${JSON.stringify(priority.field)}`);
1759
+ lines.push(" values:");
1760
+ for (const [name, value] of Object.entries(priority.values)) {
1761
+ lines.push(` ${JSON.stringify(name)}: ${value}`);
1762
+ }
1763
+ return lines;
1764
+ }
1765
+ if (priority?.source === "labels") {
1766
+ lines.push(" priority:");
1767
+ lines.push(" source: labels");
1768
+ lines.push(" labels:");
1769
+ for (const [name, value] of Object.entries(priority.labels)) {
1770
+ lines.push(` ${JSON.stringify(name)}: ${value}`);
1771
+ }
1772
+ return lines;
1773
+ }
1774
+ lines.push(" priority:");
1775
+ lines.push(" source: disabled");
1776
+ lines.push("");
1777
+ lines.push(" # Optional template: project-field priority source.");
1778
+ lines.push(" # priority:");
1779
+ lines.push(" # source: project-field");
1780
+ lines.push(" # field: Priority");
1781
+ lines.push(" # values:");
1782
+ lines.push(" # Urgent: 0");
1783
+ lines.push(" # High: 1");
1784
+ lines.push("");
1785
+ lines.push(" # Optional template: labels priority source.");
1786
+ lines.push(" # priority:");
1787
+ lines.push(" # source: labels");
1788
+ lines.push(" # labels:");
1789
+ lines.push(" # P0: 0");
1790
+ lines.push(" # P1: 1");
1791
+ return lines;
1792
+ }
1793
+ function resolveRoleAction(role) {
1794
+ switch (role) {
1795
+ case "active":
1796
+ return "Agent starts work immediately. Creates workpad and proceeds with implementation.";
1797
+ case "wait":
1798
+ return "PR created. Awaiting human review. Agent is idle.";
1799
+ case "terminal":
1800
+ return "Completed state. Agent exits.";
1801
+ case null:
1802
+ return "Role unset. Must be explicitly configured in WORKFLOW.md.";
1803
+ }
1959
1804
  }
1960
1805
 
1961
1806
  // src/skills/templates/gh-symphony-references/workflow-schema.ts
@@ -2274,6 +2119,17 @@ async function abortIfCancelled(input) {
2274
2119
  }
2275
2120
  return result;
2276
2121
  }
2122
+ var SKIP_CONTEXT_DEPRECATION = "--skip-context is deprecated and is now a no-op. Repo-local .gh-symphony/context.yaml is no longer generated.";
2123
+ var LEGACY_GH_SYMPHONY_FILES = [
2124
+ {
2125
+ relativePath: ".gh-symphony/context.yaml",
2126
+ reason: "replaced by skill-local references/"
2127
+ },
2128
+ {
2129
+ relativePath: ".gh-symphony/reference-workflow.md",
2130
+ reason: null
2131
+ }
2132
+ ];
2277
2133
  function parseInitFlags(args) {
2278
2134
  const flags = {
2279
2135
  dryRun: false,
@@ -2314,6 +2170,9 @@ function parseInitFlags(args) {
2314
2170
  }
2315
2171
  return flags;
2316
2172
  }
2173
+ function warnDeprecatedSkipContext() {
2174
+ p.log.warn(SKIP_CONTEXT_DEPRECATION);
2175
+ }
2317
2176
  async function runInitRuntimePreflight(runtime) {
2318
2177
  if (!isClaudeRuntime(runtime)) {
2319
2178
  return true;
@@ -2336,6 +2195,9 @@ async function runInitRuntimePreflight(runtime) {
2336
2195
  }
2337
2196
  var handler = async (args, options) => {
2338
2197
  const flags = parseInitFlags(args);
2198
+ if (flags.skipContext) {
2199
+ warnDeprecatedSkipContext();
2200
+ }
2339
2201
  if (flags.nonInteractive) {
2340
2202
  await runNonInteractive(flags, options);
2341
2203
  return;
@@ -2408,6 +2270,62 @@ function runRuntimePreflight(runtime) {
2408
2270
  );
2409
2271
  }
2410
2272
  }
2273
+ async function findLegacyGhSymphonyFiles(cwd) {
2274
+ const found = [];
2275
+ for (const legacyFile of LEGACY_GH_SYMPHONY_FILES) {
2276
+ try {
2277
+ await readFile3(join3(cwd, legacyFile.relativePath), "utf8");
2278
+ found.push(legacyFile.relativePath);
2279
+ } catch {
2280
+ }
2281
+ }
2282
+ return found;
2283
+ }
2284
+ async function removeLegacyGhSymphonyFiles(cwd, legacyFiles) {
2285
+ const removed = [];
2286
+ for (const relativePath of legacyFiles) {
2287
+ await rm(join3(cwd, relativePath), { force: true });
2288
+ removed.push(relativePath);
2289
+ }
2290
+ const legacyDir = join3(cwd, ".gh-symphony");
2291
+ try {
2292
+ const remaining = await readdir2(legacyDir);
2293
+ if (remaining.length === 0) {
2294
+ await rmdir(legacyDir);
2295
+ }
2296
+ } catch {
2297
+ }
2298
+ return removed;
2299
+ }
2300
+ async function promptLegacyGhSymphonyCleanup(cwd) {
2301
+ const legacyFiles = await findLegacyGhSymphonyFiles(cwd);
2302
+ if (legacyFiles.length === 0) {
2303
+ return [];
2304
+ }
2305
+ const lines = [
2306
+ "Found legacy .gh-symphony/ directory.",
2307
+ "These files are no longer used:"
2308
+ ];
2309
+ for (const legacyFile of LEGACY_GH_SYMPHONY_FILES) {
2310
+ if (!legacyFiles.includes(legacyFile.relativePath)) {
2311
+ continue;
2312
+ }
2313
+ const suffix = legacyFile.reason ? ` (${legacyFile.reason})` : "";
2314
+ lines.push(` \u2022 ${legacyFile.relativePath}${suffix}`);
2315
+ }
2316
+ lines.push("Safe to delete.");
2317
+ p.log.info(lines.join("\n"));
2318
+ const removeFiles = await abortIfCancelled(
2319
+ p.confirm({
2320
+ message: "Remove legacy .gh-symphony/ files?",
2321
+ initialValue: false
2322
+ })
2323
+ );
2324
+ if (!removeFiles) {
2325
+ return [];
2326
+ }
2327
+ return removeLegacyGhSymphonyFiles(cwd, legacyFiles);
2328
+ }
2411
2329
  async function resolveChangeStatus(path, content, mode) {
2412
2330
  try {
2413
2331
  const existing = await readFile3(path, "utf8");
@@ -2433,9 +2351,9 @@ async function writePlannedFile(file) {
2433
2351
  if (file.status === "unchanged") {
2434
2352
  return false;
2435
2353
  }
2436
- await mkdir3(dirname3(file.path), { recursive: true });
2354
+ await mkdir2(dirname2(file.path), { recursive: true });
2437
2355
  const temporaryPath = `${file.path}.tmp`;
2438
- await writeFile3(temporaryPath, file.content, "utf8");
2356
+ await writeFile2(temporaryPath, file.content, "utf8");
2439
2357
  await rename2(temporaryPath, file.path);
2440
2358
  if (file.executable) {
2441
2359
  await chmod(file.path, 493);
@@ -2774,8 +2692,7 @@ async function planEcosystem(opts) {
2774
2692
  statusField,
2775
2693
  priorityField,
2776
2694
  runtime,
2777
- skipSkills,
2778
- skipContext
2695
+ skipSkills
2779
2696
  } = opts;
2780
2697
  const priority = opts.priority ?? (priorityField ? buildProjectFieldPriority(priorityField) : buildDisabledPriority());
2781
2698
  const automaticLifecycle = toWorkflowLifecycleConfig(
@@ -2791,7 +2708,6 @@ async function planEcosystem(opts) {
2791
2708
  planningStates: defaultBlockerCheckStates
2792
2709
  }
2793
2710
  );
2794
- const ghSymphonyDir = join3(cwd, ".gh-symphony");
2795
2711
  const environment = opts.environment ?? await detectEnvironment(cwd);
2796
2712
  const files = [];
2797
2713
  files.push(
@@ -2803,44 +2719,6 @@ async function planEcosystem(opts) {
2803
2719
  executable: true
2804
2720
  })
2805
2721
  );
2806
- if (!skipContext) {
2807
- const contextYaml = buildContextYaml({
2808
- projectDetail,
2809
- statusField,
2810
- detectedEnvironment: environment,
2811
- runtime: {
2812
- agent: runtime,
2813
- agent_command: resolveShellAgentCommand(runtime)
2814
- }
2815
- });
2816
- files.push(
2817
- await planFileChange({
2818
- path: join3(ghSymphonyDir, "context.yaml"),
2819
- label: "Context metadata",
2820
- content: generateContextYamlString(contextYaml),
2821
- mode: "overwrite"
2822
- })
2823
- );
2824
- }
2825
- const referenceWorkflow = generateReferenceWorkflow({
2826
- runtime,
2827
- statusColumns: statusField.options.map((o) => ({
2828
- name: o.name,
2829
- role: null
2830
- })),
2831
- projectId: projectDetail.id,
2832
- priority,
2833
- lifecycle,
2834
- detectedEnvironment: environment
2835
- });
2836
- files.push(
2837
- await planFileChange({
2838
- path: join3(ghSymphonyDir, "reference-workflow.md"),
2839
- label: "Reference workflow",
2840
- content: referenceWorkflow,
2841
- mode: "overwrite"
2842
- })
2843
- );
2844
2722
  const skillsDir = skipSkills ? null : resolveSkillsDir(cwd, runtime);
2845
2723
  if (!skipSkills && skillsDir) {
2846
2724
  const { files: plannedSkills } = buildSkillFilePlans(
@@ -2861,8 +2739,6 @@ async function planEcosystem(opts) {
2861
2739
  role: null
2862
2740
  })),
2863
2741
  statusFieldId: statusField.id,
2864
- contextYamlPath: ".gh-symphony/context.yaml",
2865
- referenceWorkflowPath: ".gh-symphony/reference-workflow.md",
2866
2742
  detectedEnvironment: environment
2867
2743
  }
2868
2744
  );
@@ -2893,17 +2769,8 @@ async function planEcosystem(opts) {
2893
2769
  }
2894
2770
  async function writeEcosystem(opts) {
2895
2771
  const plan = await planEcosystem(opts);
2896
- await mkdir3(join3(opts.cwd, ".gh-symphony"), { recursive: true });
2897
2772
  const afterCreateHookPath = join3(opts.cwd, DEFAULT_AFTER_CREATE_HOOK_PATH);
2898
- const contextYamlPath = join3(opts.cwd, ".gh-symphony", "context.yaml");
2899
- const referenceWorkflowPath = join3(
2900
- opts.cwd,
2901
- ".gh-symphony",
2902
- "reference-workflow.md"
2903
- );
2904
2773
  let afterCreateHookWritten = false;
2905
- let contextYamlWritten = false;
2906
- let referenceWorkflowWritten = false;
2907
2774
  const skillsWritten = [];
2908
2775
  const skillsSkipped = [];
2909
2776
  for (const file of plan.files) {
@@ -2912,14 +2779,6 @@ async function writeEcosystem(opts) {
2912
2779
  afterCreateHookWritten = written;
2913
2780
  continue;
2914
2781
  }
2915
- if (file.path === contextYamlPath) {
2916
- contextYamlWritten = written;
2917
- continue;
2918
- }
2919
- if (file.path === referenceWorkflowPath) {
2920
- referenceWorkflowWritten = written;
2921
- continue;
2922
- }
2923
2782
  if (file.label.startsWith("Skill ")) {
2924
2783
  const skillName = file.label.slice("Skill ".length);
2925
2784
  if (written) {
@@ -2939,10 +2798,11 @@ async function writeEcosystem(opts) {
2939
2798
  skillsDir: plan.skillsDir,
2940
2799
  skipSkills: plan.skipSkills,
2941
2800
  afterCreateHookWritten,
2942
- contextYamlWritten,
2943
- referenceWorkflowWritten,
2801
+ contextYamlWritten: false,
2802
+ referenceWorkflowWritten: false,
2944
2803
  skillsWritten: [...new Set(skillsWritten)].sort(),
2945
- skillsSkipped: [...new Set(skillsSkipped)].sort()
2804
+ skillsSkipped: [...new Set(skillsSkipped)].sort(),
2805
+ legacyFilesRemoved: []
2946
2806
  };
2947
2807
  }
2948
2808
  function formatPrioritySummaryLines(priority) {
@@ -2994,16 +2854,6 @@ function printEcosystemSummary(result, workflowPath, opts) {
2994
2854
  ` \u2713 ${DEFAULT_AFTER_CREATE_HOOK_LABEL.padEnd(36)} ${DEFAULT_AFTER_CREATE_HOOK_PATH}`
2995
2855
  );
2996
2856
  }
2997
- if (result.contextYamlWritten) {
2998
- lines.push(
2999
- " \u2713 Context metadata .gh-symphony/context.yaml"
3000
- );
3001
- }
3002
- if (result.referenceWorkflowWritten) {
3003
- lines.push(
3004
- " \u2713 Reference workflow .gh-symphony/reference-workflow.md"
3005
- );
3006
- }
3007
2857
  if (result.skillsDir) {
3008
2858
  const relSkillsDir = relative(cwd, result.skillsDir);
3009
2859
  lines.push("");
@@ -3377,6 +3227,7 @@ async function runInteractiveStandalone(flags, _options) {
3377
3227
  printDryRunPreview(outputPath, workflowPlan, ecosystemPlan);
3378
3228
  return;
3379
3229
  }
3230
+ await promptLegacyGhSymphonyCleanup(process.cwd());
3380
3231
  await writeWorkflowPlan(workflowPlan);
3381
3232
  const ecosystemResult = await writeEcosystem({
3382
3233
  cwd: process.cwd(),
@@ -3400,7 +3251,9 @@ export {
3400
3251
  toWorkflowLifecycleConfig,
3401
3252
  validateStateMapping,
3402
3253
  abortIfCancelled,
3254
+ warnDeprecatedSkipContext,
3403
3255
  workflow_init_default,
3256
+ promptLegacyGhSymphonyCleanup,
3404
3257
  resolveStatusField,
3405
3258
  buildAutomaticStateMappings,
3406
3259
  resolvePriorityField,