Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ jobs:
source ./bin/activate-hermit
just check-acp-schema

- name: Check Config Schema is Up-to-Date
run: |
source ./bin/activate-hermit
just check-config-schema

desktop-lint:
name: Test and Lint Electron Desktop App
runs-on: macos-latest
Expand Down
22 changes: 22 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ check-everything:
cd ui/desktop && pnpm run lint:check
@echo " → Validating OpenAPI schema..."
./scripts/check-openapi-schema.sh
@echo " → Validating config schema..."
just check-config-schema
@echo ""
@echo "✅ All style checks passed!"

Expand Down Expand Up @@ -226,6 +228,26 @@ generate-acp-types: generate-acp-schema
cd ui/sdk && npx tsx generate-schema.ts
@echo "ACP TypeScript types generated in ui/sdk/src/generated/"

# Generate config.yaml JSON schema from Rust types
generate-config-schema:
@echo "Generating config.yaml JSON schema..."
cargo run -p goose --bin generate_config_schema
@echo "Config schema generated: crates/goose/config.schema.json"

# Check if config.yaml JSON schema is up-to-date
check-config-schema: generate-config-schema
#!/usr/bin/env bash
set -e
echo "Checking config schema is up-to-date..."
if ! git diff --exit-code crates/goose/config.schema.json; then
echo ""
echo "Config schema is out of date!"
echo ""
echo "Run 'just generate-config-schema' locally, then commit the changes."
exit 1
fi
echo "Config schema is up-to-date"

# Build SDK TypeScript package (schema + types + compile)
build-sdk: generate-acp-types
@echo "Compiling ACP TypeScript..."
Expand Down
33 changes: 15 additions & 18 deletions crates/goose-cli/src/commands/configure.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::recipes::github_recipe::GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY;
use cliclack::spinner;
use console::style;
use goose::agents::extension::{ToolInfo, PLATFORM_EXTENSIONS};
Expand All @@ -21,14 +20,13 @@ use goose::config::{
};
use goose::model::ModelConfig;
#[cfg(feature = "telemetry")]
use goose::posthog::{get_telemetry_choice, TELEMETRY_ENABLED_KEY};
use goose::posthog::get_telemetry_choice;
use goose::providers::base::ConfigKey;
use goose::providers::chatgpt_codex::reasoning_levels_for_model;
use goose::providers::formats::anthropic::supports_adaptive_thinking;
use goose::providers::provider_test::test_provider_configuration;
use goose::providers::{create, providers, retry_operation, RetryConfig};
use goose::session::SessionType;
use serde_json::Value;
use std::collections::HashMap;

// useful for light themes where there is no discernible colour contrast between
Expand Down Expand Up @@ -96,7 +94,7 @@ pub fn configure_telemetry_consent_dialog() -> anyhow::Result<bool> {
.initial_value(true)
.interact()?;

config.set_param(TELEMETRY_ENABLED_KEY, enabled)?;
config.set_goose_telemetry_enabled(enabled)?;

if enabled {
let _ = cliclack::log::success("Thank you for helping improve goose!");
Expand Down Expand Up @@ -1429,7 +1427,7 @@ pub fn configure_telemetry_dialog() -> anyhow::Result<()> {
.initial_value(current_choice.unwrap_or(true))
.interact()?;

config.set_param(TELEMETRY_ENABLED_KEY, enabled)?;
config.set_goose_telemetry_enabled(enabled)?;

if enabled {
cliclack::outro("Telemetry enabled - thank you for helping improve goose!")?;
Expand All @@ -1456,15 +1454,15 @@ pub fn configure_tool_output_dialog() -> anyhow::Result<()> {

match tool_log_level {
"high" => {
config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.8)?;
config.set_goose_cli_min_priority(0.8)?;
cliclack::outro("Showing tool output of high importance only.")?;
}
"medium" => {
config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.2)?;
config.set_goose_cli_min_priority(0.2)?;
cliclack::outro("Showing tool output of medium importance.")?;
}
"all" => {
config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.0)?;
config.set_goose_cli_min_priority(0.0)?;
cliclack::outro("Showing all tool output.")?;
}
_ => unreachable!(),
Expand All @@ -1482,7 +1480,7 @@ pub fn configure_keyring_dialog() -> anyhow::Result<()> {
);
}

let currently_disabled = config.get_param::<String>("GOOSE_DISABLE_KEYRING").is_ok();
let currently_disabled = config.get_goose_disable_keyring().is_ok();

let current_status = if currently_disabled {
"Disabled (using file-based storage)"
Expand Down Expand Up @@ -1513,14 +1511,14 @@ pub fn configure_keyring_dialog() -> anyhow::Result<()> {
match storage_option {
"keyring" => {
// Set to empty string to enable keyring (absence or empty = enabled)
config.set_param("GOOSE_DISABLE_KEYRING", Value::String("".to_string()))?;
config.set_goose_disable_keyring("".to_string())?;
cliclack::outro("Secret storage set to system keyring (secure)")?;
let _ =
cliclack::log::info("You may need to restart goose for this change to take effect");
}
"file" => {
// Set the disable flag to use file storage
config.set_param("GOOSE_DISABLE_KEYRING", Value::String("true".to_string()))?;
config.set_goose_disable_keyring("true".to_string())?;
cliclack::outro(format!(
"Secret storage set to file ({}). Keep this file secure!",
secrets_path.display(),
Expand Down Expand Up @@ -1745,11 +1743,10 @@ pub async fn configure_tool_permissions_dialog() -> anyhow::Result<()> {
}

fn configure_recipe_dialog() -> anyhow::Result<()> {
let key_name = GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY;
let config = Config::global();
let default_recipe_repo = std::env::var(key_name)
let default_recipe_repo = std::env::var("GOOSE_RECIPE_GITHUB_REPO")
.ok()
.or_else(|| config.get_param(key_name).unwrap_or(None));
.or_else(|| config.get_goose_recipe_github_repo().unwrap_or(None));
let mut recipe_repo_input = cliclack::input(
"Enter your goose recipe GitHub repo (owner/repo): eg: my_org/goose-recipes",
)
Expand All @@ -1759,17 +1756,17 @@ fn configure_recipe_dialog() -> anyhow::Result<()> {
}
let input_value: String = recipe_repo_input.interact()?;
if input_value.clone().trim().is_empty() {
config.delete(key_name)?;
config.delete("GOOSE_RECIPE_GITHUB_REPO")?;
} else {
config.set_param(key_name, &input_value)?;
config.set_goose_recipe_github_repo(Some(input_value))?;
}
Ok(())
}

pub fn configure_max_turns_dialog() -> anyhow::Result<()> {
let config = Config::global();

let current_max_turns: u32 = config.get_param("GOOSE_MAX_TURNS").unwrap_or(1000);
let current_max_turns: u32 = config.get_goose_max_turns().unwrap_or(1000);

let max_turns_input: String =
cliclack::input("Set maximum number of agent turns without user input:")
Expand All @@ -1788,7 +1785,7 @@ pub fn configure_max_turns_dialog() -> anyhow::Result<()> {
.interact()?;

let max_turns: u32 = max_turns_input.parse()?;
config.set_param("GOOSE_MAX_TURNS", max_turns)?;
config.set_goose_max_turns(max_turns)?;

cliclack::outro(format!(
"Set maximum turns to {} - goose will ask for input after {} consecutive actions",
Expand Down
1 change: 0 additions & 1 deletion crates/goose-cli/src/recipes/github_recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ pub enum RecipeSource {
GitHub,
}

pub const GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY: &str = "GOOSE_RECIPE_GITHUB_REPO";
pub fn retrieve_recipe_from_github(
recipe_name: &str,
recipe_repo_full_name: &str,
Expand Down
3 changes: 1 addition & 2 deletions crates/goose-cli/src/recipes/search_recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use goose::recipe::read_recipe_file_content::RecipeFile;

use super::github_recipe::{
list_github_recipes, retrieve_recipe_from_github, RecipeInfo, RecipeSource,
GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY,
};
use goose::recipe::local_recipes::{list_local_recipes, load_local_recipe_file};

Expand All @@ -20,7 +19,7 @@ pub fn load_recipe_file(recipe_name: &str) -> Result<RecipeFile> {

fn configured_github_recipe_repo() -> Option<String> {
let config = Config::global();
match config.get_param(GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY) {
match config.get_goose_recipe_github_repo() {
Ok(Some(recipe_repo_full_name)) => Some(recipe_repo_full_name),
_ => None,
}
Expand Down
4 changes: 2 additions & 2 deletions crates/goose-cli/src/session/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ async fn configure_session_prompts(
.await;
}

let system_prompt_file: Option<String> = config.get_param("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
let system_prompt_file: Option<String> = config.get_goose_system_prompt_file_path().ok();
if let Some(ref path) = system_prompt_file {
let override_prompt = std::fs::read_to_string(path).unwrap_or_else(|e| {
output::render_error(&format!(
Expand Down Expand Up @@ -723,7 +723,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
}
});

let debug_mode = session_config.debug || config.get_param("GOOSE_DEBUG").unwrap_or(false);
let debug_mode = session_config.debug || config.get_goose_debug().unwrap_or(false);

let session = CliSession::new(
Arc::try_unwrap(agent_ptr).unwrap_or_else(|_| panic!("There should be no more references")),
Expand Down
2 changes: 1 addition & 1 deletion crates/goose-cli/src/session/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl rustyline::ConditionalEventHandler for CtrlCHandler {

pub fn get_newline_key() -> char {
Config::global()
.get_param::<String>("GOOSE_CLI_NEWLINE_KEY")
.get_goose_cli_newline_key()
.ok()
.and_then(|s| s.chars().next())
.map(|c| c.to_ascii_lowercase())
Expand Down
12 changes: 5 additions & 7 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1398,9 +1398,7 @@ impl CliSession {
let context_limit = model_config.context_limit();

let config = Config::global();
let show_cost = config
.get_param::<bool>("GOOSE_CLI_SHOW_COST")
.unwrap_or(false);
let show_cost = config.get_goose_cli_show_cost().unwrap_or(false);

let provider_name = config
.get_goose_provider()
Expand Down Expand Up @@ -1793,7 +1791,7 @@ fn format_logging_notification(
Some("response_generated") => {
let config = Config::global();
let min_priority = config
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
.get_goose_cli_min_priority()
.ok()
.unwrap_or(output::DEFAULT_MIN_PRIORITY);

Expand Down Expand Up @@ -1859,7 +1857,7 @@ fn display_log_notification(
} else if ntype == "shell_output" {
let config = Config::global();
let min_priority = config
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
.get_goose_cli_min_priority()
.ok()
.unwrap_or(output::DEFAULT_MIN_PRIORITY);

Expand Down Expand Up @@ -1966,7 +1964,7 @@ async fn get_reasoner() -> Result<Arc<dyn Provider>, anyhow::Error> {
let config = Config::global();

// Try planner-specific provider first, fall back to default provider
let provider = if let Ok(provider) = config.get_param::<String>("GOOSE_PLANNER_PROVIDER") {
let provider = if let Ok(provider) = config.get_goose_planner_provider() {
provider
} else {
println!("WARNING: GOOSE_PLANNER_PROVIDER not found. Using default provider...");
Expand All @@ -1976,7 +1974,7 @@ async fn get_reasoner() -> Result<Arc<dyn Provider>, anyhow::Error> {
};

// Try planner-specific model first, fall back to default model
let model = if let Ok(model) = config.get_param::<String>("GOOSE_PLANNER_MODEL") {
let model = if let Ok(model) = config.get_goose_planner_model() {
model
} else {
println!("WARNING: GOOSE_PLANNER_MODEL not found. Using default model...");
Expand Down
20 changes: 10 additions & 10 deletions crates/goose-cli/src/session/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ impl Theme {
fn as_str(&self) -> String {
match self {
Theme::Light => Config::global()
.get_param::<String>("GOOSE_CLI_LIGHT_THEME")
.get_goose_cli_light_theme()
.unwrap_or(DEFAULT_CLI_LIGHT_THEME.to_string()),
Theme::Dark => Config::global()
.get_param::<String>("GOOSE_CLI_DARK_THEME")
.get_goose_cli_dark_theme()
.unwrap_or(DEFAULT_CLI_DARK_THEME.to_string()),
Theme::Ansi => "base16".to_string(),
}
Expand Down Expand Up @@ -70,20 +70,20 @@ thread_local! {
std::env::var("GOOSE_CLI_THEME").ok()
.map(|val| Theme::from_config_str(&val))
.unwrap_or_else(||
Config::global().get_param::<String>("GOOSE_CLI_THEME").ok()
Config::global().get_goose_cli_theme().ok()
.map(|val| Theme::from_config_str(&val))
.unwrap_or(Theme::Ansi)
)
);
static SHOW_FULL_TOOL_OUTPUT: RefCell<bool> = RefCell::new(
Config::global().get_param::<bool>("GOOSE_SHOW_FULL_OUTPUT").unwrap_or(false)
Config::global().get_goose_show_full_output().unwrap_or(false)
);
}

pub fn set_theme(theme: Theme) {
let config = Config::global();
config
.set_param("GOOSE_CLI_THEME", theme.as_config_string())
.set_goose_cli_theme(theme.as_config_string())
.expect("Failed to set theme");
CURRENT_THEME.with(|t| *t.borrow_mut() = theme);

Expand All @@ -94,7 +94,7 @@ pub fn set_theme(theme: Theme) {
Theme::Ansi => "ansi",
};

if let Err(e) = config.set_param("GOOSE_CLI_THEME", theme_str) {
if let Err(e) = config.set_goose_cli_theme(theme_str) {
eprintln!("Failed to save theme setting to config: {}", e);
}
}
Expand Down Expand Up @@ -126,7 +126,7 @@ impl ThinkingIndicator {
let spinner = cliclack::spinner();
let hint = style("(Ctrl+C to interrupt)").dim();
if Config::global()
.get_param("RANDOM_THINKING_MESSAGES")
.get_random_thinking_messages()
.unwrap_or(true)
{
spinner.start(format!(
Expand Down Expand Up @@ -177,7 +177,7 @@ pub fn hide_thinking() {
}

pub fn run_status_hook(status: &str) {
if let Ok(hook) = Config::global().get_param::<String>("GOOSE_STATUS_HOOK") {
if let Ok(hook) = Config::global().get_goose_status_hook() {
let status = status.to_string();
std::thread::spawn(move || {
#[cfg(target_os = "windows")]
Expand Down Expand Up @@ -449,7 +449,7 @@ pub fn goose_mode_message(text: &str) {

fn should_show_thinking() -> bool {
Config::global()
.get_param::<bool>("GOOSE_CLI_SHOW_THINKING")
.get_goose_cli_show_thinking()
.unwrap_or(false)
&& std::io::stdout().is_terminal()
}
Expand Down Expand Up @@ -507,7 +507,7 @@ fn render_tool_response(resp: &ToolResponse, debug: bool) {
}

let min_priority = config
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
.get_goose_cli_min_priority()
.ok()
.unwrap_or(DEFAULT_MIN_PRIORITY);

Expand Down
6 changes: 2 additions & 4 deletions crates/goose-server/src/tunnel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ impl TunnelManager {
}

fn get_auto_start() -> bool {
Config::global()
.get_param("tunnel_auto_start")
.unwrap_or(false)
Config::global().get_tunnel_auto_start().unwrap_or(false)
}

fn get_secret() -> Option<String> {
Expand Down Expand Up @@ -200,7 +198,7 @@ impl TunnelManager {

pub fn set_auto_start(auto_start: bool) -> anyhow::Result<()> {
Config::global()
.set_param("tunnel_auto_start", auto_start)
.set_tunnel_auto_start(auto_start)
.map_err(|e| anyhow::anyhow!("Failed to save tunnel config: {}", e))
}

Expand Down
4 changes: 4 additions & 0 deletions crates/goose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ path = "src/bin/analyze_cli.rs"
name = "build_canonical_models"
path = "src/providers/canonical/build_canonical_models.rs"

[[bin]]
name = "generate_config_schema"
path = "src/bin/generate_config_schema.rs"

[package.metadata.cargo-machete]

ignored = [
Expand Down
Loading
Loading