Skip to content

Expose agent skills through but-api - #15192

Open
schacon wants to merge 2 commits into
agents-cli-skill-capabilitiesfrom
agents-cli-api
Open

Expose agent skills through but-api#15192
schacon wants to merge 2 commits into
agents-cli-skill-capabilitiesfrom
agents-cli-api

Conversation

@schacon

@schacon schacon commented Aug 5, 2026

Copy link
Copy Markdown
Member

The transport layer between but-skill and the desktop app. Stacked on #15190.

The theme for review

Two narrow questions: is the API shape right, and is registration complete on every transport? Most of the line count is documented DTOs and generated SDK types, so it reads faster than the diff suggests.

Seven commands

New non-legacy crates/but-api/src/agents.rs:

Command Purpose
agents_status detect agents, report skill state per scope
agent_skill_install / agent_skill_uninstall per framework, per scope
agent_skills_update refresh outdated skills in place
agent_policy_get / agent_policy_set read and write the workflow policy
cli_install_state / uninstall_cli the but symlink

Mutations return the refreshed AgentsStatus so the UI needs one round trip.

Design decisions worth a look

The project is an optional id, not a Context. These commands are meaningful without a project — the global settings screen manages $HOME skills before any repository is open. agents_status reports both scopes when a project is given and global only otherwise, and lists detected agents first. (#[but_api] also does not support Option<&Context>; the macro only recognises owned/&/&mut Context.)

Uninstall removes every discovered installation, not the canonical path. Skills are identified by SKILL.md frontmatter, so one installed into a custom folder name lives elsewhere and would otherwise be orphaned. agent_skills_update does the same thing for the same reason — writing the canonical path would leave the outdated copy in place and add a second one beside it.

agent_policy_set only rewrites files that already hold a managed block. Saving preferences should never seed GitButler steering into an agent's instruction file the user never set up.

agent_policy_get reports divergence when two instruction files disagree — which happens when someone hand-edits one — rather than silently showing whichever sorted first.

Registration

Tauri invoke_handler, but-server routes, and regenerated SDK types. napi needs nothing; #[but_api] functions are auto-discovered through the but-api/napi feature.

Also: a settings group, and a bug fix

Adds an agents settings group with skillsPromptDismissed, backing the startup prompt in the next PR. A new group rather than a stray boolean on ui (which is window chrome), since the tab will grow more knobs.

While adding update_agents to but-server's dispatch I found update_ui was never registered there — it went into Tauri when it was added but not into the server, so any non-Tauri caller fell through to the catch-all and silently did nothing. Fixed in the same match.

No new test for the settings default: ensure_default_settings_covers_all_fields already fails when a field has no entry in defaults.jsonc, which turns that omission from a startup panic into a test failure. Confirmed by removing the entry and watching it fail.

Verification

cargo check --workspace --all-targets and cargo clippy --workspace clean; pnpm build:sdk regenerated and committed.

schacon added 2 commits August 5, 2026 12:32
The desktop app had no way to reach any of this: skill discovery, install,
uninstall, and the workflow policy all lived behind the CLI. Adds a but_api
module so a settings screen can read structured state and change it one
framework at a time, instead of shelling out and parsing output.

Seven commands: agents_status, agent_skill_install, agent_skill_uninstall,
agent_policy_get, agent_policy_set, cli_install_state, and uninstall_cli.
Mutations return the refreshed status so the UI needs a single round trip.

The project is passed as an optional id rather than a Context because these
commands are meaningful without one - the global settings screen manages $HOME
skills before any repository is open. agents_status reports both scopes when a
project is given and global only otherwise, and lists detected agents first.

Two deliberate restrictions. Uninstall removes every installation discovered
for a format rather than just the canonical path, since a skill installed into
a custom folder name is still ours and would otherwise be orphaned. And
agent_policy_set only rewrites instruction files that already hold a managed
block, so saving preferences never seeds GitButler steering into an agent file
the user never set up.

agent_policy_get reports divergence when two instruction files disagree, which
happens when a user hand-edits one, rather than silently showing whichever
sorted first.
Backs the startup prompt with a persisted flag, so a user who declines the
offer to set up agent skills is not asked again.

Uses a new settings group rather than a stray boolean on `ui`, which is about
window chrome. The tab this supports will grow more knobs, and a group keeps
them together.

Also adds the "update_ui" arm to but-server's command dispatch. It was
registered in Tauri when it was added but never here, so any non-Tauri caller
fell through to the catch-all and silently did nothing. Included with this
commit because both arms are the same contiguous change to that match.

No new test for the default: the existing ensure_default_settings_covers_all_fields
already fails when a field has no entry in defaults.jsonc, which is what turns
that omission from a startup panic into a test failure. Verified by removing
the entry and watching it fail.
Copilot AI lite review requested due to automatic review settings August 5, 2026 11:25
@github-actions github-actions Bot added rust Pull requests that update Rust code @gitbutler/desktop labels Aug 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new agents API has a couple of correctness gaps (policy divergence detection and uninstall scope handling) and the described agent_skills_update command is not implemented/registered across transports.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds a new but-api surface for managing coding-agent skills and workflow policy (plus CLI symlink inspection/uninstall) so GUI callers can render and mutate agent state without interactive CLI prompts, and wires it through Tauri + but-server while extending app settings with a new agents group.

Changes:

  • Introduces crates/but-api/src/agents.rs with DTOs and commands for agent/skill discovery, install/uninstall, policy get/set, and CLI symlink state.
  • Registers the new agents commands on the Tauri invoke handler and the but-server HTTP routes; updates generated SDK types and bindings where applicable.
  • Adds an agents settings group (skillsPromptDismissed) and fixes a missing update_ui registration in but-server’s command dispatch.
File summaries
File Description
packages/but-sdk/src/generated/linear/index.js Exposes updateAgents in the native binding export list.
packages/but-sdk/src/generated/linear/index.d.ts Adds agent-related DTO types and updateAgents typing; extends AppSettings with agents.
packages/but-sdk/src/generated/graph/index.js Exposes updateAgents in the native binding export list.
packages/but-sdk/src/generated/graph/index.d.ts Adds agent-related DTO types and updateAgents typing; extends AppSettings with agents.
crates/gitbutler-tauri/src/settings.rs Adds Tauri command update_agents to persist the new settings group.
crates/gitbutler-tauri/src/main.rs Registers new agents::* Tauri invoke handlers.
crates/but-testsupport/src/sandbox.rs Initializes the new agents settings field in test sandbox settings.
crates/but-settings/src/lib.rs Adds agents: Agents to AppSettings.
crates/but-settings/src/app_settings.rs Defines the persisted Agents settings struct.
crates/but-settings/src/api.rs Adds AgentsUpdate input DTO and AppSettingsWithDiskSync::update_agents.
crates/but-settings/assets/defaults.jsonc Adds defaults for the new agents.skillsPromptDismissed setting.
crates/but-server/src/lib.rs Registers agents HTTP routes and fixes missing update_ui command dispatch registration; adds update_agents dispatch.
crates/but-napi/src/settings.rs Adds NAPI update_agents settings mutation.
crates/but-api/src/lib.rs Exposes the new agents module from but-api.
crates/but-api/src/legacy/settings.rs Adds legacy settings handler update_agents for non-Tauri callers.
crates/but-api/src/agents.rs Implements the new agents/skills/policy/CLI transport API and associated JSON DTOs.
apps/desktop/src/lib/settings/appSettings.ts Adds SettingsService.updateAgents() invoking update_agents.
Review details
  • Files reviewed: 13/17 changed files
  • Comments generated: 4
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

// Two files disagreeing means the user edited one by hand or
// set them up separately; surface it rather than silently
// showing whichever came first alphabetically.
Some(first) if first.selected != options.selected => diverged = true,
Comment on lines +521 to +525
if let Some(format) = framework.format(matches!(scope, Scope::Global)) {
for path in but_skill::status::find_format_installations(format, &base) {
but_skill::install::remove_skill_files(&path)?;
}
}
Comment on lines +748 to +752
.route(
"/cli_install_state",
but_post(agents::cli_install_state_cmd),
)
.route("/uninstall_cli", but_post(agents::uninstall_cli_cmd))
Comment on lines +338 to +342
agents::tauri_cli_install_state::cli_install_state,
agents::tauri_uninstall_cli::uninstall_cli,
agents::tauri_agents_status::agents_status,
agents::tauri_agent_skill_install::agent_skill_install,
agents::tauri_agent_skill_uninstall::agent_skill_uninstall,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

@gitbutler/desktop rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants