Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7434c6a
chore: improve dx, WIP
viadezo1er Apr 1, 2026
af7d7ff
gitting stuff, reformulate this commit message
viadezo1er Apr 2, 2026
c4359fc
remove unused code
viadezo1er Apr 2, 2026
0f87ec0
fix CI
viadezo1er Apr 2, 2026
243a81d
fix bugs ; claude, codex, cursor work, opencode doesn't
viadezo1er Apr 2, 2026
2967c9c
fix: yoloy flag
viadezo1er Apr 2, 2026
36c04fe
chore: make behavior more consistent and logical
viadezo1er Apr 3, 2026
b3c46e7
interactive flag to use the interactive wizard
viadezo1er Apr 3, 2026
5122ca6
fix: no-instrument flag didn't work and crashed
viadezo1er Apr 3, 2026
5f74638
fix: bt setup with OAuth doesn't change bt auth profiles output
viadezo1er Apr 3, 2026
b5db1f8
fix: json flag didn't work
viadezo1er Apr 4, 2026
d2333db
fix: broke cargo clippy
viadezo1er Apr 6, 2026
41af72c
feat: when only one coding agent is on path, use it and do not prompt…
viadezo1er Apr 6, 2026
a391f2c
chore: help message to explain what are org, project
viadezo1er Apr 6, 2026
5898225
chore: detect coding agents by PATH only, add bt setup --no-instrumen…
viadezo1er Apr 6, 2026
5b894b2
Merge branch 'cedric/better-dx' of https://github.com/braintrustdata/…
viadezo1er Apr 6, 2026
d2f7fbc
feat: add branding when bt setup is called
viadezo1er Apr 7, 2026
fbe30c0
chore: mcp installation disabled by default
viadezo1er Apr 7, 2026
7afc977
chore: better error message when trying to launch an agent not on PATH
viadezo1er Apr 7, 2026
ab99617
feat: can create a new project instead of using an existing one
viadezo1er Apr 7, 2026
52c33ad
fix: can create a project when there are not projects in the org
viadezo1er Apr 7, 2026
d9decba
chore: remove useless info message
viadezo1er Apr 7, 2026
eff2254
chore: being outside of a git repo prints a warning but behavior is i…
viadezo1er Apr 7, 2026
73568b4
chore: update help message for bt setup
viadezo1er Apr 7, 2026
a13f636
feat: create an API key when logging with OAuth so the users doesn't …
viadezo1er Apr 8, 2026
e1e112f
fix: non interactive mode asking for scope by default
viadezo1er Apr 8, 2026
c431de5
chore: when changing org/project, remove the prompt asking wether to …
viadezo1er Apr 8, 2026
0ba3ab5
chore: improve help message
viadezo1er Apr 8, 2026
70ae3ba
chor,e test: improve agent prompt
viadezo1er Apr 8, 2026
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
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ install-success-msg = ""

[dev-dependencies]
tempfile = "3"
rexpect = "0.5"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = ["Win32_Storage_FileSystem"] }
5 changes: 5 additions & 0 deletions ascii-logo-blue-small.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
 ███ ███
███ ███
███ ███
███ ███
███ ███
10 changes: 6 additions & 4 deletions skills/sdk-install/braintrust-url-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

### Experiments

`https://www.braintrust.dev/app/{org}/p/{project}/experiments/{experiment_name}?r={root_span_id}&s={span_id}`
`https://BRAINTRUST_APP_URL/{org}/p/{project}/experiments/{experiment_name}?r={root_span_id}&s={span_id}`

### Datasets

`https://www.braintrust.dev/app/{org}/p/{project}/datasets/{dataset_name}?r={root_span_id}`
`https://BRAINTRUST_APP_URL/{org}/p/{project}/datasets/{dataset_name}?r={root_span_id}`

### Project Logs

`https://www.braintrust.dev/app/{org}/p/{project}/logs?r={root_span_id}&s={span_id}`
`https://BRAINTRUST_APP_URL/{org}/p/{project}/logs?r={root_span_id}&s={span_id}`

## Legacy Object URLs

`https://www.braintrust.dev/app/object?object_type=...&object_id=...&id=...`
`https://BRAINTRUST_APP_URL/object?object_type=...&object_id=...&id=...`

## URL Parameters

Expand All @@ -25,6 +25,8 @@
| r | The root_span_id - identifies a trace |
| s | The span_id - identifies a specific span within the trace |
| id | Legacy parameter for root_span_id in object URLs |
| BRAINTRUST_APP_URL | url where the app is accessible, www.braintrust.dev/app for non self-hosted instances. See the env variable BRAINTRUST_APP_URL 9and use www.braintrust.dev/app if it is not set) |


## Notes

Expand Down
22 changes: 13 additions & 9 deletions skills/sdk-install/instrument-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ If not set, **abort installation immediately**.
Determine the project language using concrete signals:

- `package.json` → TypeScript
- `requirements.txt` or `pyproject.toml` → Python
- `requirements.txt`, `setup.py` or `pyproject.toml` → Python
- `pom.xml` or `build.gradle` → Java
- `go.mod` → Go
- `Gemfile` → Ruby
Expand Down Expand Up @@ -80,7 +80,7 @@ Read the install guide for the detected language from the local docs:
Requirements:

- Pin an exact SDK version (resolve via package manager).
- Modify only dependency files and a minimal application entry point (e.g., main/bootstrap).
- Modify only dependency files and a minimal application entry point (e.g., main/bootstrap). Auto-instrument the app (except for Java and C# which don't support auto-instrumentation).
- Do not change unrelated code.

---
Expand Down Expand Up @@ -108,13 +108,7 @@ Most language SDKs print a direct URL to the emitted trace after the app runs. C

If the SDK does not print a URL, construct one manually using the URL format documented in `{SDK_INSTALL_DIR}/braintrust-url-formats.md`:

```
https://www.braintrust.dev/app/{org}/p/{project_name}/logs?r={root_span_id}
```

- `org`: your Braintrust organization slug
- `project_name`: the project name set in code
- `root_span_id`: the trace/span ID returned or logged by the SDK
See `{SDK_INSTALL_DIR}/braintrust-url-formats.md` for the url format.

---

Expand All @@ -127,4 +121,14 @@ Summarize:
- What logs/traces were emitted
- The Braintrust permalink (required)

---

### 7. Next Steps

Tell the user:

- Braintrust agent skills have been installed and are available to your coding agent to help you integrate Braintrust into your product.
- The Braintrust MCP server can be added to make your coding agent even more helpful when working with Braintrust — run `bt setup mcp` to install it. More information at https://www.braintrust.dev/docs/integrations/developer-tools/mcp
- For more information on Braintrust, visit https://www.braintrust.dev/docs

{WORKFLOW_CONTEXT}
10 changes: 3 additions & 7 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ pub struct BaseArgs {
#[arg(long, global = true)]
pub json: bool,

/// Suppress non-essential output
#[arg(long, short = 'q', env = "BRAINTRUST_QUIET", global = true, value_parser = clap::builder::BoolishValueParser::new(), default_value_t = false)]
pub quiet: bool,
/// Verbose mode — set at runtime by subcommands that support it
#[arg(skip)]
pub verbose: bool,

/// Disable ANSI color output
#[arg(long, env = "BRAINTRUST_NO_COLOR", global = true, value_parser = clap::builder::BoolishValueParser::new(), default_value_t = false)]
Expand Down Expand Up @@ -44,10 +44,6 @@ pub struct BaseArgs {
#[arg(long, global = true)]
pub prefer_profile: bool,

/// Disable all interactive prompts
#[arg(long, global = true)]
pub no_input: bool,

/// Override API URL (or via BRAINTRUST_API_URL)
#[arg(
long,
Expand Down
30 changes: 11 additions & 19 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ struct AuthLogoutArgs {
}

pub async fn run(base: BaseArgs, args: AuthArgs) -> Result<()> {
if !base.json {
crate::ui::set_quiet(false);
}
match args.command {
AuthCommand::Login(login_args) => run_login_set(&base, login_args).await,
AuthCommand::Refresh => run_login_refresh(&base).await,
Expand Down Expand Up @@ -405,11 +408,7 @@ fn maybe_warn_api_key_override(base: &BaseArgs) {

if let Some(profile_name) = ignored_profile {
eprintln!(
"Warning: using --api-key/BRAINTRUST_API_KEY credentials; selected profile '{profile_name}' is ignored for this command. Use --prefer-profile or unset BRAINTRUST_API_KEY.",
);
} else {
eprintln!(
"Warning: using --api-key/BRAINTRUST_API_KEY credentials for this command. Use --prefer-profile or unset BRAINTRUST_API_KEY."
"Info: using --api-key/BRAINTRUST_API_KEY credentials; selected profile '{profile_name}' is ignored for this command. Use --prefer-profile or unset BRAINTRUST_API_KEY to use a profile with OAuth login.",
);
}
}
Expand Down Expand Up @@ -779,17 +778,7 @@ async fn run_login_oauth(base: &BaseArgs, args: AuthLoginArgs) -> Result<()> {
Ok(())
}

pub async fn login_interactive(base: &mut BaseArgs) -> Result<String> {
let methods = ["OAuth (browser)", "API key"];
let selected = ui::fuzzy_select("Select login method", &methods, 0)?;

if selected == 0 {
login_interactive_oauth(base).await
} else {
login_interactive_api_key(base).await
}
}

#[allow(dead_code)]
async fn login_interactive_api_key(base: &mut BaseArgs) -> Result<String> {
let api_key = prompt_api_key()?;

Expand Down Expand Up @@ -825,7 +814,7 @@ async fn login_interactive_api_key(base: &mut BaseArgs) -> Result<String> {
Ok(profile_name)
}

async fn login_interactive_oauth(base: &mut BaseArgs) -> Result<String> {
pub(crate) async fn login_interactive_oauth(base: &mut BaseArgs) -> Result<String> {
let api_url = base
.api_url
.clone()
Expand Down Expand Up @@ -863,7 +852,9 @@ async fn login_interactive_oauth(base: &mut BaseArgs) -> Result<String> {

let _ = open::that(&authorize_url);
eprintln!("Complete authorization in your browser.");
eprintln!();
eprintln!("{}", dialoguer::console::style(&authorize_url).dim());
eprintln!();

let callback = collect_oauth_callback(listener, is_ssh_session()).await?;
if let Some(error) = callback.error {
Expand Down Expand Up @@ -1579,6 +1570,7 @@ fn select_login_org(
}
}));
let label_refs: Vec<&str> = labels.iter().map(String::as_str).collect();
println!("\n\nA Braintrust organization is usually a team or a company.");
let selection = ui::fuzzy_select("Select organization", &label_refs, 0)?;
if allow_cross_org && selection == 0 {
return Ok(None);
Expand Down Expand Up @@ -1717,6 +1709,7 @@ async fn collect_oauth_callback(
let pasted = Input::<String>::new()
.with_prompt("Callback URL/query/JSON (press Enter to wait for automatic callback)")
.allow_empty(true)
.report(false)
.interact_text()
.context("failed to read callback URL")?;
if pasted.trim().is_empty() {
Expand Down Expand Up @@ -2580,14 +2573,13 @@ mod tests {
fn make_base() -> BaseArgs {
BaseArgs {
json: false,
quiet: false,
verbose: false,
no_color: false,
profile: None,
project: None,
org_name: None,
api_key: None,
prefer_profile: false,
no_input: false,
api_url: None,
app_url: None,
env_file: None,
Expand Down
3 changes: 1 addition & 2 deletions src/functions/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3359,14 +3359,13 @@ mod tests {
fn test_base_args() -> BaseArgs {
BaseArgs {
json: false,
quiet: false,
verbose: false,
no_color: false,
profile: None,
org_name: None,
project: None,
api_key: None,
prefer_profile: false,
no_input: false,
api_url: None,
app_url: None,
env_file: None,
Expand Down
11 changes: 2 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ Flags
--profile <PROFILE> Use a saved login profile [env: BRAINTRUST_PROFILE]
-o, --org <ORG> Override active org [env: BRAINTRUST_ORG_NAME]
-p, --project <PROJECT> Override active project [env: BRAINTRUST_DEFAULT_PROJECT]
-q, --quiet Suppress non-essential output
--json Output as JSON
--no-color Disable ANSI color output
--no-input Disable all interactive prompts
Expand Down Expand Up @@ -249,14 +248,8 @@ fn configure_output(base: &BaseArgs) {
ui::set_animations_enabled(false);
}

if base.quiet {
ui::set_quiet(true);
ui::set_animations_enabled(false);
}

if base.no_input {
ui::set_no_input(true);
}
ui::set_quiet(true);
ui::set_animations_enabled(false);

if disable_color {
dialoguer::console::set_colors_enabled(false);
Expand Down
Loading