-
Notifications
You must be signed in to change notification settings - Fork 7.2k
feat(agents): add Goose AI agent support #2015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
29fa832
79bdc39
b8fc3d9
57da3d4
5b4d283
2c7c3ba
0edef9d
fdf9e15
7ff5780
5148bc4
9430815
3d13436
969aa84
90d1ebd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,7 @@ set -euo pipefail | |
| # Usage: .github/workflows/scripts/create-release-packages.sh <version> | ||
| # Version argument should include leading 'v'. | ||
| # Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built. | ||
| # AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf junie codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob vibe qodercli kimi trae pi iflow generic (default: all) | ||
| # AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf junie codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob vibe qodercli kimi trae pi iflow goose generic (default: all) | ||
| # SCRIPTS : space or comma separated subset of: sh ps (default: both) | ||
| # Examples: | ||
| # AGENTS=claude SCRIPTS=sh $0 v0.2.0 | ||
|
|
@@ -116,6 +116,28 @@ generate_commands() { | |
| echo "$body" > "$output_dir/speckit.$name.$ext" ;; | ||
| agent.md) | ||
| echo "$body" > "$output_dir/speckit.$name.$ext" ;; | ||
| yaml) | ||
| # Generate Goose recipe format YAML | ||
| local title | ||
| # Use awk for reliable title casing (sed \b is not portable) | ||
| title=$(echo "$name" | tr '_-' ' ' | awk '{for (i=1; i<=NF; i++) $i=toupper(substr($i,1,1)) substr($i,2)}1') | ||
| # Indent every line of body for valid YAML block scalar syntax | ||
| indented_body=$(printf '%s\n' "$body" | sed 's/^/ /') | ||
| cat > "$output_dir/speckit.$name.$ext" <<YAML_EOF | ||
|
Comment on lines
+121
to
+126
|
||
| version: 1.0.0 | ||
| title: "$title" | ||
| description: "$description" | ||
| author: | ||
| contact: "spec-kit" | ||
| extensions: | ||
| - type: builtin | ||
| name: developer | ||
| activities: | ||
| - "Spec-Driven Development" | ||
| prompt: | | ||
| ${indented_body} | ||
| YAML_EOF | ||
furkankoykiran marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ;; | ||
| esac | ||
| done | ||
| } | ||
|
|
@@ -330,6 +352,9 @@ build_variant() { | |
| iflow) | ||
| mkdir -p "$base_dir/.iflow/commands" | ||
| generate_commands iflow md "\$ARGUMENTS" "$base_dir/.iflow/commands" "$script" ;; | ||
| goose) | ||
| mkdir -p "$base_dir/.goose/recipes" | ||
| generate_commands goose yaml "{{args}}" "$base_dir/.goose/recipes" "$script" ;; | ||
| generic) | ||
| mkdir -p "$base_dir/.speckit/commands" | ||
| generate_commands generic md "\$ARGUMENTS" "$base_dir/.speckit/commands" "$script" ;; | ||
|
|
@@ -339,7 +364,7 @@ build_variant() { | |
| } | ||
|
|
||
| # Determine agent list | ||
| ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf junie codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob vibe qodercli kimi trae pi iflow generic) | ||
| ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf junie codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob vibe qodercli kimi trae pi iflow goose generic) | ||
| ALL_SCRIPTS=(sh ps) | ||
furkankoykiran marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| validate_subset() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -162,6 +162,12 @@ class CommandRegistrar: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "format": "markdown", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "args": "$ARGUMENTS", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "extension": ".md" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "goose": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "dir": ".goose/recipes", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "format": "yaml", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "args": "{{args}}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "extension": ".yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
furkankoykiran marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -329,6 +335,62 @@ def render_toml_command( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "\n".join(toml_lines) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def render_yaml_command( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| frontmatter: dict, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: str, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| source_id: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Render command in YAML format for Goose recipes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| frontmatter: Command frontmatter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: Command body content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| source_id: Source identifier (extension or preset ID) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Formatted YAML recipe file content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get title from frontmatter or generate from command name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title = frontmatter.get("title", "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not title and "name" in frontmatter: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Generate title from command name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title = frontmatter["name"].replace("_", " ").replace("-", " ").title() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+354
to
+359
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get title from frontmatter or generate from command name | |
| title = frontmatter.get("title", "") | |
| if not title and "name" in frontmatter: | |
| # Generate title from command name | |
| title = frontmatter["name"].replace("_", " ").replace("-", " ").title() | |
| # Get title from frontmatter or generate from available identifiers | |
| title = frontmatter.get("title", "") | |
| # Prefer explicit name if title is missing | |
| if not title and "name" in frontmatter and frontmatter["name"]: | |
| title = ( | |
| str(frontmatter["name"]) | |
| .replace("_", " ") | |
| .replace("-", " ") | |
| .title() | |
| ) | |
| # Fallback to other likely identifier fields in frontmatter | |
| if not title: | |
| for key in ("id", "command"): | |
| value = frontmatter.get(key) | |
| if value: | |
| title = ( | |
| str(value) | |
| .replace("_", " ") | |
| .replace("-", " ") | |
| .title() | |
| ) | |
| break | |
| # Final fallback: derive a title from the source_id (e.g., filename or path) | |
| if not title and source_id: | |
| source_str = str(source_id) | |
| source_name = Path(source_str).name | |
| source_stem = Path(source_name).stem | |
| title = ( | |
| source_stem.replace("_", " ").replace("-", " ").title() | |
| if source_stem | |
| else source_str | |
| ) | |
| # Absolute last resort to avoid empty titles | |
| if not title: | |
| title = "Command" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the
yamlcase,ArgFormatisn’t applied to the$ARGUMENTSplaceholder that appears in the command bodies (templates use$ARGUMENTSin the “User Input” block). This means the generated Goose.yamlrecipes will still contain$ARGUMENTSeven though Goose’s config specifies{{args}}. Consider replacing$ARGUMENTSwith$ArgFormatwhen building$body(for YAML and TOML outputs) so packaged templates match the runtime placeholder conversion.