Skip to content
Merged
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
14 changes: 14 additions & 0 deletions crates/loomweave-cli/src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use loomweave_federation::config::{
select_provider_with_env,
};
use loomweave_federation::filigree::FiligreeHttpClient;
use loomweave_federation::warpline::WarplineMcpClient;
use loomweave_llm::{
ApiEmbeddingProvider, ApiEmbeddingProviderConfig, ClaudeCliProvider, ClaudeCliProviderConfig,
CodexCliProvider, CodexCliProviderConfig, EmbeddingProvider, EmbeddingProviderError,
Expand Down Expand Up @@ -91,6 +92,12 @@ pub fn run(path: &Path, config_path: Option<&Path>) -> Result<()> {
)
.context("build Filigree HTTP client")?;

// Read-only Warpline churn consumer for the high-churn / recently-changed
// surfaces. `None` when disabled (the default) — the surfaces degrade
// honestly. Enrich-only, dependency-sink: nothing flows loomweave→warpline.
let warpline_client =
WarplineMcpClient::from_config(&config.integrations.warpline, Some(&project_root));

let diagnostics = loomweave_mcp::DiagnosticsContext {
llm: llm_diagnostics,
filigree: filigree_resolution,
Expand Down Expand Up @@ -127,6 +134,7 @@ pub fn run(path: &Path, config_path: Option<&Path>) -> Result<()> {
llm_provider,
semantic_search_state(&config.semantic_search, embedding_provider),
filigree_client,
warpline_client,
diagnostics,
loomweave_mcp::McpToolPolicy {
enable_write_tools: config.serve.mcp.enable_write_tools,
Expand Down Expand Up @@ -199,6 +207,7 @@ fn spawn_mcp_stdio(
llm_provider: Option<Arc<dyn LlmProvider>>,
semantic_search: Option<SemanticSearchState>,
filigree_client: Option<FiligreeHttpClient>,
warpline_client: Option<WarplineMcpClient>,
diagnostics: loomweave_mcp::DiagnosticsContext,
tool_policy: loomweave_mcp::McpToolPolicy,
analyze_config_path: Option<PathBuf>,
Expand All @@ -215,6 +224,7 @@ fn spawn_mcp_stdio(
llm_provider,
semantic_search,
filigree_client,
warpline_client,
diagnostics,
tool_policy,
analyze_config_path,
Expand All @@ -234,6 +244,7 @@ fn run_mcp_stdio(
llm_provider: Option<Arc<dyn LlmProvider>>,
semantic_search: Option<SemanticSearchState>,
filigree_client: Option<FiligreeHttpClient>,
warpline_client: Option<WarplineMcpClient>,
diagnostics: loomweave_mcp::DiagnosticsContext,
tool_policy: loomweave_mcp::McpToolPolicy,
analyze_config_path: Option<PathBuf>,
Expand Down Expand Up @@ -271,6 +282,9 @@ fn run_mcp_stdio(
if let Some(client) = filigree_client {
state = state.with_filigree_client(Arc::new(client));
}
if let Some(client) = warpline_client {
state = state.with_warpline_client(Arc::new(client));
}
state = state.with_diagnostics(diagnostics);

let serve_result = loomweave_mcp::serve_stdio_with_state_on_runtime(
Expand Down
50 changes: 50 additions & 0 deletions crates/loomweave-federation/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,14 @@ impl ClaudePermissionMode {
#[serde(default, deny_unknown_fields)]
pub struct IntegrationsConfig {
pub filigree: FiligreeConfig,
/// Warpline (the federation's temporal/change authority) churn-count read,
/// consumed at read time by `entity_high_churn_list` /
/// `entity_recent_change_list`. Read-only, enrich-only, dependency-sink:
/// loomweave never stores a warpline fact (the seam's HARD RULE — loomweave
/// retains no cross-run history; see the 2026-06-13 warpline interface lock
/// §1, §5). Default disabled — the churn surfaces stay honest-empty with a
/// missing-signal note until an operator opts in.
pub warpline: WarplineConfig,
}

#[derive(Debug, Clone, PartialEq, Default, Deserialize)]
Expand Down Expand Up @@ -754,6 +762,48 @@ impl Default for FiligreeConfig {
}
}

/// Read-time consumption of Warpline's FROZEN churn-count read
/// (`warpline_entity_churn_count_get`, `warpline.entity_churn_count.v1`). This
/// is a *read-only* seam: loomweave asks warpline for per-entity change counts
/// to rank `entity_high_churn_list` / `entity_recent_change_list`, joins them at
/// read time, and retains NOTHING (the loomweave↔warpline HARD RULE — loomweave
/// holds no cross-run history). There is deliberately NO write/emit flag here:
/// unlike the Filigree seam, nothing flows loomweave→warpline.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct WarplineConfig {
/// Whether the churn surfaces consult warpline. Default `false`: the
/// surfaces stay honest-empty (with a missing-signal note naming warpline)
/// until an operator opts in. A missing/unreachable warpline with this
/// `true` degrades the same way — never an error, never empty-as-clean.
pub enabled: bool,
/// Operator-configured actor identity. **Reserved, not sent on the wire:**
/// `actor` is not in warpline's FROZEN `warpline_entity_churn_count_get`
/// schema (`additionalProperties: false`), so the churn read carries none.
/// The field is retained (rather than removed) so an existing `loomweave.yaml`
/// that sets `integrations.warpline.actor` still parses under
/// `deny_unknown_fields` — warpline's own dogfood config sets it.
pub actor: String,
/// Per-call timeout (seconds) for the warpline churn subprocess round-trip.
/// Warpline is an MCP-stdio member (no HTTP read API), launched as a
/// subprocess and driven over **newline-delimited** MCP JSON-RPC (the
/// transport `warpline-mcp` actually speaks). A warpline child that accepts
/// the connection and never answers would otherwise hang the read; this
/// bound makes a transport fault degrade to the honest `warpline-unreachable`
/// response instead. Default 10s; a `0` is floored to 1s by the client.
pub timeout_seconds: u64,
}

impl Default for WarplineConfig {
fn default() -> Self {
Self {
enabled: false,
actor: "loomweave-mcp".to_owned(),
timeout_seconds: 10,
}
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProviderSelection {
Disabled,
Expand Down
1 change: 1 addition & 0 deletions crates/loomweave-federation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod filigree_url;
pub mod loomweave_port;
pub mod loomweave_url;
pub mod scan_results;
pub mod warpline;
Loading