Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions crates/goose/src/agents/builtin_skills/goose_doc_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
name: goose-doc-guide
description: Reference goose documentation to create, configure, or explain goose-specific features like recipes, extensions, sessions, and providers. You MUST fetch relevant goose docs before answering. You MUST NOT rely on training data or assumptions for any goose-specific fields, values, names, syntax, or commands.
---

Use this skill when working with **goose-specific features**:
- Creating or editing recipes
- Configuring extensions or providers
- Explaining how goose features work
- Any goose configuration or setup task

Do NOT use this skill for:
- General coding tasks unrelated to goose
- Running existing recipes (just run them directly)

## Steps (COMPLETE ALL BEFORE RESPONDING)
1. **Fetch official docs**
- Fetch the doc map from `https://block.github.io/goose/goose-docs-map.md`
- Search the doc map for pages relevant to the user's topic and get the paths for these pages
- Use the EXACT paths from the doc map. For example:
- If doc map shows: `docs/guides/sessions/session-management.md`
- Fetch: `https://block.github.io/goose/docs/guides/sessions/session-management.md`
- Do NOT modify or guess paths.
- **ONLY fetch paths that are explicitly listed in the doc map - do not guess or infer URLs**
- Make multiple fetch calls in parallel and save to temp files
- Use the temp files for subsequent searches instead of re-fetching

2. **Create/modify content**
- For goose configuration files:
- Consult schema/field reference documentation first
- **Search the fetched docs to extract the complete schema for each element you plan to use**
- Extract example snippets to understand usage patterns
- Create your configuration based on reference specs, following example patterns
- **⚠️ STOP: Before showing the user, verify output content MUST match the schema and reference in goose the official documentation:**

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awkward phrasing: "reference in goose the official documentation" should be "reference in the official goose documentation".

Suggested change
- **⚠️ STOP: Before showing the user, verify output content MUST match the schema and reference in goose the official documentation:**
- **⚠️ STOP: Before showing the user, verify output content MUST match the schema and reference in the official goose documentation:**

Copilot uses AI. Check for mistakes.
- [ ] Field names match exactly as shown in docs
- [ ] Required fields/properties are present
- [ ] Value formats match examples (YAML/JSON syntax, data types, etc.)
- **If ANY verification fails, revise and repeat this step until ALL verifications pass**
- **DO NOT present unverified output to the user**
- Use only fetched docs for all goose-specific details

3. **MANDATORY VERIFICATION - DO THIS BEFORE STEP 4**
Before writing your final answer:
- [ ] You ONLY present goose-specific information that is explicitly stated in the fetched documentation. If you cannot identify the documentation page that supports a detail, you must NOT include it.
- [ ] add instructions/commands if: (a) user explicitly asked for them, AND (b) they appear in the fetched docs
- You MUST NOT rely on training data or assumptions for any goose-specific fields, values, names, syntax, or commands.
- [ ] For EVERY goose-specific command in your answer: Search feteched files to verify it exists
- [ ] For EVERY goose-specific field in your answer: Search feteched files to verify it exists
- [ ] For EVERY usage instruction in your answer: Search feteched files to verify it exists

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in "feteched" should be "fetched".

Suggested change
- [ ] For EVERY goose-specific command in your answer: Search feteched files to verify it exists
- [ ] For EVERY goose-specific field in your answer: Search feteched files to verify it exists
- [ ] For EVERY usage instruction in your answer: Search feteched files to verify it exists
- [ ] For EVERY goose-specific command in your answer: Search fetched files to verify it exists
- [ ] For EVERY goose-specific field in your answer: Search fetched files to verify it exists
- [ ] For EVERY usage instruction in your answer: Search fetched files to verify it exists

Copilot uses AI. Check for mistakes.
- [ ] If you cannot verify something: Remove it, unless the user explicitly asked for it (then state "I could not find documentation for [X]")

4. **Provide your answer and include a "Verification Completed" section showing which checks passed**
- Which checks passed
- How you verified each field exists in the documentation

5. **List documentation links**
- Only include docs actually used
- Remove `.md` suffix from URLs
- Example: If you fetched `https://block.github.io/goose/docs/guides/sessions/session-management.md`, list it as `https://block.github.io/goose/docs/guides/sessions/session-management`
11 changes: 11 additions & 0 deletions crates/goose/src/agents/builtin_skills/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use include_dir::{include_dir, Dir};

static BUILTIN_SKILLS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/agents/builtin_skills");

pub fn get_all_builtin_skills() -> Vec<&'static str> {
BUILTIN_SKILLS_DIR
.files()
.filter(|f| f.path().extension().is_some_and(|ext| ext == "md"))

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mod.rs file will be included in the embedded directory by include_dir!. This means the filter on line 8 will see mod.rs (without .md extension) in addition to .md files. While this works because mod.rs is filtered out by the extension check, it's worth noting that the directory being embedded includes the Rust source file itself.

This is not a bug but could be surprising. Consider adding a comment explaining that the macro embeds the entire directory including mod.rs, which is filtered out at runtime.

Copilot uses AI. Check for mistakes.
.filter_map(|f| f.contents_utf8())
.collect()
}
1 change: 1 addition & 0 deletions crates/goose/src/agents/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod agent;
mod builtin_skills;
pub(crate) mod chatrecall_extension;
pub(crate) mod code_execution_extension;
pub mod execute_commands;
Expand Down
32 changes: 31 additions & 1 deletion crates/goose/src/agents/skills_extension.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::builtin_skills;
use crate::agents::extension::PlatformExtensionContext;
use crate::agents::mcp_client::{Error, McpClientTrait, McpMeta};
use crate::config::paths::Paths;
Expand Down Expand Up @@ -64,17 +65,38 @@ impl SkillsClient {
instructions: Some(String::new()),
};

let mut skills = Self::load_builtin_skills();

let directories = Self::get_default_skill_directories()
.into_iter()
.filter(|d| d.exists())
.collect::<Vec<_>>();
let skills = Self::discover_skills_in_directories(&directories);
let fs_skills = Self::discover_skills_in_directories(&directories);
skills.extend(fs_skills);

Comment on lines +76 to 77

Copilot AI Jan 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filesystem skills will silently override builtin skills with the same name. When skills.extend(fs_skills) is called (line 76), any filesystem skill with a name matching a builtin skill (like "goose-doc-guide") will replace the builtin version. This could confuse users who expect the builtin skill to be available.

Consider either: (1) documenting this behavior so users understand the override mechanism, or (2) inverting the order so filesystem skills are loaded first and builtin skills supplement them, or (3) detecting conflicts and logging a warning when a filesystem skill shadows a builtin skill.

Suggested change
skills.extend(fs_skills);
// Merge filesystem-discovered skills, warning if they shadow builtin skills.
for (name, skill) in fs_skills {
if skills.contains_key(&name) {
eprintln!(
"Warning: filesystem skill \"{}\" overrides builtin skill with the same name",
name
);
}
skills.insert(name, skill);
}

Copilot uses AI. Check for mistakes.
let mut client = Self { info, skills };
client.info.instructions = Some(client.generate_instructions());
Ok(client)
}

fn load_builtin_skills() -> HashMap<String, Skill> {
let mut skills = HashMap::new();
for content in builtin_skills::get_all_builtin_skills() {
if let Ok((metadata, body)) = Self::parse_frontmatter(content) {
skills.insert(
metadata.name.clone(),
Skill {
metadata,
body,
directory: PathBuf::new(),
supporting_files: vec![],
},
);
Comment on lines +86 to +95

Copilot AI Jan 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors during built-in skill parsing are silently ignored. If a built-in skill file has invalid frontmatter, it will fail to load without any logging or error reporting. Consider logging parse failures or returning a Result to surface issues during development.

Suggested change
if let Ok((metadata, body)) = Self::parse_frontmatter(content) {
skills.insert(
metadata.name.clone(),
Skill {
metadata,
body,
directory: PathBuf::new(),
supporting_files: vec![],
},
);
match Self::parse_frontmatter(content) {
Ok((metadata, body)) => {
skills.insert(
metadata.name.clone(),
Skill {
metadata,
body,
directory: PathBuf::new(),
supporting_files: vec![],
},
);
}
Err(e) => {
tracing::warn!(error = ?e, "Failed to parse built-in skill frontmatter; built-in skill will be skipped");
}

Copilot uses AI. Check for mistakes.
}
}
skills
}

fn get_default_skill_directories() -> Vec<PathBuf> {
let mut dirs = Vec::new();

Expand Down Expand Up @@ -826,4 +848,12 @@ Working dir goose content
.body
.contains("Working dir goose content"));
}

#[test]
fn test_builtin_skills_loaded() {
let skills = SkillsClient::load_builtin_skills();

assert!(!skills.is_empty());
assert!(skills.contains_key("goose-doc-guide"));
}
}
Loading