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
8 changes: 4 additions & 4 deletions rust/crates/sift_cli/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ switch back to the default; each change applies to every detected client.
Doctor reports both settings. Mixed modes or profiles are errors rather than
values the CLI silently resolves.

The `agent` command and `mcp` sidecar remain behind the `mcp` Cargo feature until
the open-beta release explicitly changes that policy.
The `agent` command and `mcp` sidecar ship in every build. The prior `mcp`
Cargo feature was removed in 0.4.0.

## Updating the skill

Expand All @@ -63,8 +63,8 @@ pressure, so every line should change what the agent does.
From the repository root:

```sh
cargo build -p sift_cli --features mcp
cargo test -p sift_cli --features mcp cmd::agent
cargo build -p sift_cli
cargo test -p sift_cli cmd::agent
./target/debug/sift-cli agent doctor
```

Expand Down
47 changes: 40 additions & 7 deletions rust/crates/sift_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,46 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [v0.4.0] - August 5, 2026

### What's New

- Added `sift-cli agent install`, `update`, `doctor`, and `uninstall` for
stateless, lockstep management of the release-matched Sift skill and MCP
sidecar across detected Claude Code, Codex, Cursor, and OpenCode clients.
Cursor and OpenCode support is new in this release.
- Added safe-by-default, lockstep MCP access controls: install defaults to
read-only, update preserves the existing mode, explicit flags enable or
disable destructive tools for all detected clients, and doctor reports mixed
modes.
- Consolidated the duplicated agent instructions into one canonical skill at
`assets/skills/sift/SKILL.md`.
- The `agent` command and `mcp` sidecar are no longer behind a Cargo feature
and ship in every build. `cargo build -p sift_cli` now includes them by
default; the prior `--features mcp` flag is gone.
- Split the installed skill into a router (`SKILL.md`) plus dedicated
reference files under `references/` for better token efficiency and clearer
agent guidance.
- Added a `list_users` MCP tool. Combined with the other list tools, this
supports patterns like "runs I created" or "assets created by <teammate>"
without guessing IDs.
- Added report-template MCP tools: `list_report_templates`,
`create_report_template`, and `update_report_template`. Templates bundle a
reusable set of rules that any `create_report` call can inherit via
`report_template_id`.
- Improved MCP filter guidance: agents default `is_archived == false` on
every list call, use regex/case-insensitive matching
(`name.matches("(?i)...")`) instead of `==` for text search, and always
pass `limit` to keep results within the context window.
- MCP tool calls no longer proceed on an empty list result. Empty lists
surface to the user for guidance instead of triggering a follow-up call
with an empty ID.
- Added an opt-in `test-reports` Cargo feature on `sift_mcp` (forwarded from
`sift_cli`) that gates the test-report tools. Off by default; enable with
`--features test-reports` when a build needs them.
- Added `app_uri` as a required profile field. Profile setup now asks for the
web app origin. `sift-cli agent doctor` treats a missing value as an error and
prints the config command. `sift-cli mcp` does not expose tools for an
incomplete profile. MCP links now use only the selected profile value. The
MCP tool-list error includes the config command.
- Removed the project-scoped `install agent-skills` workflow. Existing Sift
blocks in project `AGENTS.md` files must be removed manually because the new
lifecycle is user-scoped.
Expand All @@ -24,11 +53,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Removed the MCP server, built-in prompt, and agent skill pages from the
bundled `sift-cli` documentation. The agent-facing tool surface is documented
in the installed skill instead.
- Added `app_uri` as a required profile field. Profile setup now asks for the
web app origin. `sift-cli agent doctor` treats a missing value as an error and
prints the config command. `sift-cli mcp` does not expose tools for an
incomplete profile. MCP links now use only the selected profile value. The
MCP tool-list error includes the config command.
- Replaced the ASCII loading indicator with a braille spinner across the
`agent` commands.

### Bug Fixes

- `create_report` now actually starts the rule evaluation for the new report
instead of leaving it in the initial state.
- Various fixes surfaced during the internal alpha across the MCP data,
reports, and rules tools.

## [v0.3.0] - July 13, 2026

Expand Down
4 changes: 2 additions & 2 deletions rust/crates/sift_cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[features]
mcp = []
test-reports = ["sift_mcp/test-reports"]

[package]
name = "sift_cli"
version = "0.3.0"
version = "0.4.0"
authors.workspace = true
edition.workspace = true
categories.workspace = true
Expand Down
6 changes: 0 additions & 6 deletions rust/crates/sift_cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,14 @@ pub enum Cmd {
Install(InstallCmd),

/// Manage the Sift integration for detected AI coding clients
#[cfg(feature = "mcp")]
#[command(subcommand)]
Agent(AgentCmd),

/// Start the Sift MCP server
#[cfg(feature = "mcp")]
#[command(hide = true)]
Mcp(McpArgs),
}

#[cfg(feature = "mcp")]
#[derive(clap::Args)]
pub struct McpArgs {
/// Expose destructive tools (updates, archives, restores). When omitted,
Expand All @@ -101,7 +98,6 @@ pub enum InstallCmd {
}

/// Manage Sift's release-matched skill and MCP sidecar as one bundle.
#[cfg(feature = "mcp")]
#[derive(Subcommand)]
pub enum AgentCmd {
/// Install every detected client in safe mode using the default profile unless selected
Expand All @@ -117,15 +113,13 @@ pub enum AgentCmd {
Uninstall,
}

#[cfg(feature = "mcp")]
#[derive(clap::Args)]
pub struct AgentInstallArgs {
/// Enable tools that modify or archive resources for every detected MCP client
#[arg(long)]
pub allow_destructive: bool,
}

#[cfg(feature = "mcp")]
#[derive(clap::Args)]
pub struct AgentUpdateArgs {
/// Enable tools that modify or archive resources for every detected MCP client
Expand Down
1 change: 0 additions & 1 deletion rust/crates/sift_cli/src/cmd/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ fn apply_profile_updates(
Ok(())
}

#[cfg(feature = "mcp")]
pub(super) fn inspect_app_uri(profile: Option<&str>) -> Result<AppUriState> {
let path = get_config_file_path()?;
let contents = read_to_string(path).context("failed to read config file")?;
Expand Down
9 changes: 1 addition & 8 deletions rust/crates/sift_cli/src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
use crate::BIN_NAME;
#[cfg(feature = "mcp")]
use crate::util::app_uri::infer_app_uri;
use crate::util::app_uri::normalize_app_uri;
use crate::util::app_uri::{infer_app_uri, normalize_app_uri};
use anyhow::{Context as AnyhowContext, Result, anyhow};
use crossterm::style::Stylize;
use std::{fs::read_to_string, io::ErrorKind, path::Path};
use toml::{Table, Value};

#[cfg(feature = "mcp")]
pub mod agent;
pub mod config;
pub mod doc;
pub mod export;
pub mod import;
pub mod install;
#[cfg(feature = "mcp")]
pub mod mcp;
pub mod ping;
pub mod version;
Expand Down Expand Up @@ -125,15 +121,13 @@ impl Context {
})
}

#[cfg(feature = "mcp")]
pub fn require_app_uri(&self, profile: Option<&str>) -> Result<&str> {
self.app_uri
.as_deref()
.ok_or_else(|| anyhow!(app_uri_guidance(profile, &self.rest_uri)))
}
}

#[cfg(feature = "mcp")]
fn app_uri_guidance(profile: Option<&str>, rest_uri: &str) -> String {
let profile_name = profile.unwrap_or("default");
let profile_flag = profile.map_or_else(String::new, |profile| format!("--profile {profile} "));
Expand Down Expand Up @@ -264,7 +258,6 @@ apikey = "key"
);
}

#[cfg(feature = "mcp")]
#[test]
fn mcp_requires_app_uri_with_profile_guidance() {
let known = r#"
Expand Down
8 changes: 1 addition & 7 deletions rust/crates/sift_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ use util::tty::Output;

use clap::{CommandFactory, Parser};

#[cfg(feature = "mcp")]
use crate::cli::AgentCmd;
use crate::cli::InstallCmd;
use crate::cli::{AgentCmd, InstallCmd};

const BIN_NAME: &str = "sift-cli";

Expand Down Expand Up @@ -44,7 +42,6 @@ where
runtime.block_on(fut)
}

#[allow(dead_code)]
fn run_future_mt<F>(fut: F) -> Result<ExitCode>
where
F: Future<Output = Result<ExitCode>> + 'static,
Expand Down Expand Up @@ -82,7 +79,6 @@ fn run(clargs: cli::Args) -> Result<ExitCode> {
cli::CompletionsCmd::Update => return cmd::install::completions::update(),
},
},
#[cfg(feature = "mcp")]
Cmd::Agent(cmd) => match cmd {
AgentCmd::Install(args) => return cmd::agent::install(clargs.profile, args),
AgentCmd::Update(args) => {
Expand All @@ -96,8 +92,6 @@ fn run(clargs: cli::Args) -> Result<ExitCode> {

let ctx = Context::new(clargs.profile.clone(), clargs.disable_tls)?;

// Mcp Server
#[cfg(feature = "mcp")]
if let Cmd::Mcp(args) = cmd {
let app_uri = match ctx.require_app_uri(clargs.profile.as_deref()) {
Ok(app_uri) => app_uri.to_string(),
Expand Down
Loading