--- sidebar_position: 1 title: GDK Overview sidebar_label: Overview description: Build with goose providers in Rust, Python, and Kotlin. --- # GDK The goose Development Kit (GDK) exposes goose's provider layer as a library so you can call models, stream completions, and compact conversations from your own application. One Rust crate, `goose-sdk`, is the source of every language binding. Python and Kotlin are generated from it with [UniFFI](https://github.com/mozilla/uniffi-rs), so all three languages share the same types, behavior, and version number. See the [API Reference](/docs/gdk/api-reference) for the complete surface in your language of choice. :::info Alpha The GDK is in alpha. The surface may change between `0.x` releases. Pin an exact version and check the API reference version selector when upgrading. ::: ## What you can do - Construct providers for OpenAI, Anthropic, Groq, Databricks, or any [declarative provider](#declarative-providers) defined in JSON - Stream a completion chunk by chunk, including tool calls and reasoning output - Request a single non-streaming completion - Compact a long conversation into a summary so it can continue past the model's context window - Capture provider request logs as JSONL ## Install ### Rust ```bash cargo add goose-sdk ``` By default the crate re-exports the Agent Client Protocol (ACP) wire types for talking to `goose acp` over stdio. Enable the `uniffi` feature for the in-process provider API documented in the reference: ```bash cargo add goose-sdk --features uniffi ``` ### Python ```bash pip install goose-sdk ``` The package installs as `goose-sdk` and imports as `goose`. Wheels bundle the native library, so there is nothing else to build. Requires Python 3.9+. ```python import goose ``` ### Kotlin / JVM ```kotlin dependencies { implementation("io.github.aaif-goose:gdk:") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") } ``` The artifact version matches the Rust crate version. Classes live in the `io.github.aaif_goose` package. The jar bundles native libraries for macOS (arm64, x86-64), Linux (arm64, x86-64), and Windows (x86-64). On JDK 24+, add `--enable-native-access=ALL-UNNAMED` because the GDK loads its native library through JNA. ## Quickstart Each example builds a provider, sends one message, and prints the streamed response. ### Python ```python import asyncio from goose import ( MessageContent, MessageRole, ProviderMessage, ProviderModelConfig, StreamChunk, openai_default_model, openai_provider, ) async def main() -> None: provider = openai_provider(api_key="...") model = ProviderModelConfig(model_name=openai_default_model()) messages = [ ProviderMessage( role=MessageRole.USER, content=[MessageContent.Text(text="What is the capital of France?")], ) ] stream = await provider.stream(model, "You are a geography expert.", messages, []) while chunk := await stream.next_chunk(): if isinstance(chunk, StreamChunk.TextChunk): print(chunk.text, end="") asyncio.run(main()) ``` ### Kotlin ```kotlin import io.github.aaif_goose.MessageContent import io.github.aaif_goose.MessageRole import io.github.aaif_goose.ProviderMessage import io.github.aaif_goose.ProviderModelConfig import io.github.aaif_goose.StreamChunk import io.github.aaif_goose.streamFlow import io.github.aaif_goose.providers.openai.defaultModel import io.github.aaif_goose.providers.openai.provider as openAiProvider import kotlinx.coroutines.runBlocking fun main() = runBlocking { val provider = openAiProvider(System.getenv("OPENAI_API_KEY")) val model = ProviderModelConfig(modelName = defaultModel()) val messages = listOf( ProviderMessage( role = MessageRole.USER, content = listOf(MessageContent.Text(text = "What is the capital of France?")), ), ) provider.streamFlow(model, "You are a geography expert.", messages) .collect { chunk -> if (chunk is StreamChunk.TextChunk) print(chunk.text) } } ``` ### Rust ```rust use goose_sdk::bindings::{ openai_default_model, openai_provider, MessageContent, MessageRole, ProviderMessage, ProviderModelConfig, StreamChunk, }; #[tokio::main] async fn main() -> Result<(), Box> { let provider = openai_provider(std::env::var("OPENAI_API_KEY")?)?; let model = ProviderModelConfig { model_name: openai_default_model(), ..Default::default() }; let messages = vec![ProviderMessage { role: MessageRole::User, content: vec![MessageContent::Text { text: "What is the capital of France?".to_string(), }], }]; let stream = provider .stream(model, "You are a geography expert.".to_string(), messages, vec![]) .await?; while let Some(chunk) = stream.next_chunk().await? { if let StreamChunk::TextChunk { text } = chunk { print!("{text}"); } } Ok(()) } ``` ## Kotlin idioms The Kotlin package adds a few conveniences on top of the generated bindings: | Kotlin API | Equivalent generated call | | --- | --- | | `provider.streamFlow(model, system, messages, tools)` | `stream(...)` plus a `nextChunk()` loop, as a `Flow` | | `providers.openai.provider(apiKey)` | `openaiProvider(apiKey)` | | `providers.openai.defaultModel()` | `openaiDefaultModel()` | | `providers.anthropic.provider(apiKey, baseUrl, betaHeaders)` | `anthropicProvider(...)` | | `providers.groq.provider(apiKey)` | `groqProvider(apiKey)` | | `providers.databricks.provider(host, token)` | `databricksProvider(host, token)` | `tools` defaults to an empty list in the Kotlin helpers, and suspending functions map to Kotlin coroutines. Errors surface as `GooseException` subclasses. ## Declarative providers Any provider that speaks an OpenAI- or Anthropic-compatible API can be defined in JSON and loaded without new Rust code: ```python provider = goose.declarative_provider_from_json(open("deepseek.json").read()) ``` Environment variable placeholders such as `${DEEPSEEK_API_KEY}` in the JSON are resolved when the provider is constructed. ## Streaming model `stream()` returns a `ProviderStream`. Call `next_chunk()` until it returns `None` to consume the response: | Chunk | Meaning | | --- | --- | | `TextChunk` | Assistant text | | `ToolChunk` | A tool call request with JSON arguments | | `ThinkingChunk` / `RedactedThinkingChunk` | Reasoning output | | `EndChunk` | Stream finished, carries final token `Usage` | | `ErrorChunk` | Mid-stream failure, carries a `GooseStreamError` | Errors raised before the stream starts are thrown as `GooseError` (`GooseException` in Kotlin). Errors that occur mid-stream arrive as an `ErrorChunk` instead. ## Next steps - [API Reference](/docs/gdk/api-reference) — every function, type, and error - [goose in ACP clients](/docs/guides/acp-clients) — drive the full goose agent over the Agent Client Protocol