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
18 changes: 18 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ jobs:
- name: clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings

- name: Trust-surface — loomweave-core must not link an HTTP client
# PRD-0001 / clarion-141e9c08c8: the plugin-supervisor + SEI crate must
# not carry an outbound HTTP client; provider HTTP lives in loomweave-llm.
# `--prefix none` flattens the tree so the anchor matches an indented dep
# (a plain `^reqwest` against the tree output never matches and would pass
# vacuously). `reqwest` stays legitimate in federation/cli — this is a
# per-crate ban cargo-deny's [bans] cannot express.
run: |
set -euo pipefail
# Capture first so a `cargo tree` failure exits the step (under `set -e`)
# instead of being swallowed by the pipe and read as "no reqwest".
deps="$(cargo tree -p loomweave-core --edges normal --prefix none)"
if grep -qE '^reqwest v' <<<"$deps"; then
echo "::error::loomweave-core links reqwest; the provider HTTP must stay in loomweave-llm (PRD-0001)"
exit 1
fi
echo "OK: loomweave-core has no reqwest in its dependency tree"

- name: install cargo-nextest
uses: taiki-e/install-action@e310bff3ef77234d477d6bb655da153a5c49d1db

Expand Down
21 changes: 18 additions & 3 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 @@ -3,6 +3,7 @@ resolver = "3"
members = [
"crates/loomweave-analysis",
"crates/loomweave-core",
"crates/loomweave-llm",
"crates/loomweave-federation",
"crates/loomweave-storage",
"crates/loomweave-cli",
Expand Down
1 change: 1 addition & 0 deletions crates/loomweave-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ axum.workspace = true
blake3.workspace = true
clap.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-llm = { path = "../loomweave-llm", version = "1.3.1" }
loomweave-analysis = { path = "../loomweave-analysis", version = "1.3.1" }
loomweave-federation = { path = "../loomweave-federation", version = "1.3.1" }
loomweave-mcp = { path = "../loomweave-mcp", version = "1.3.1" }
Expand Down
9 changes: 5 additions & 4 deletions crates/loomweave-cli/src/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ use uuid::Uuid;
use loomweave_core::plugin::host::FINDING_PLUGIN_ABORTED;
use loomweave_core::{
AcceptedEdge, AcceptedEntity, AnalyzeFileOutcome, CrashLoopBreaker, CrashLoopState,
DiscoveredPlugin, EmbeddingProvider, FINDING_DISABLED_CRASH_LOOP, HostError, HostFinding,
UnresolvedCallSite, discover,
DiscoveredPlugin, FINDING_DISABLED_CRASH_LOOP, HostError, HostFinding, UnresolvedCallSite,
discover,
};
use loomweave_llm::EmbeddingProvider;
use loomweave_storage::{
DEFAULT_BATCH_SIZE, DEFAULT_CHANNEL_CAPACITY, EmbeddingKey, EmbeddingStore, GitRename,
NewEntityDescriptor, PriorIndexEntry, SeiBindingRecord, SeiDecision, SeiLineageEntry,
Expand Down Expand Up @@ -8061,8 +8062,8 @@ mod tests {
async fn semantic_embedding_population_skips_fresh_sidecar_rows() {
use std::sync::Arc;

use loomweave_core::{EmbeddingProvider, EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_federation::config::SemanticSearchConfig;
use loomweave_llm::{EmbeddingProvider, EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_storage::{EmbeddingKey, EmbeddingStore, pragma, schema};

let project = tempfile::tempdir().unwrap();
Expand Down Expand Up @@ -8130,8 +8131,8 @@ mod tests {
async fn semantic_embedding_population_skips_briefing_blocked_entities() {
use std::sync::Arc;

use loomweave_core::{EmbeddingProvider, EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_federation::config::SemanticSearchConfig;
use loomweave_llm::{EmbeddingProvider, EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_storage::{pragma, schema};

let project = tempfile::tempdir().unwrap();
Expand Down
12 changes: 6 additions & 6 deletions crates/loomweave-cli/src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ use std::thread;
use std::time::Duration;

use anyhow::{Context, Result, anyhow};
use loomweave_core::{
ApiEmbeddingProvider, ApiEmbeddingProviderConfig, ClaudeCliProvider, ClaudeCliProviderConfig,
CodexCliProvider, CodexCliProviderConfig, EmbeddingProvider, EmbeddingProviderError,
LlmProvider, OpenRouterProvider, OpenRouterProviderConfig, Recording, RecordingProvider,
TrafficLoggingProvider,
};
use loomweave_federation::config::{
LlmConfig, McpConfig, ProviderSelection, SemanticProviderKind, SemanticSearchConfig,
select_provider_with_env,
};
use loomweave_federation::filigree::FiligreeHttpClient;
use loomweave_llm::{
ApiEmbeddingProvider, ApiEmbeddingProviderConfig, ClaudeCliProvider, ClaudeCliProviderConfig,
CodexCliProvider, CodexCliProviderConfig, EmbeddingProvider, EmbeddingProviderError,
LlmProvider, OpenRouterProvider, OpenRouterProviderConfig, Recording, RecordingProvider,
TrafficLoggingProvider,
};
use loomweave_storage::{DEFAULT_BATCH_SIZE, DEFAULT_CHANNEL_CAPACITY, ReaderPool, Writer};

pub fn run(path: &Path, config_path: Option<&Path>) -> Result<()> {
Expand Down
6 changes: 2 additions & 4 deletions crates/loomweave-cli/tests/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ use std::time::{Duration, Instant};

use assert_cmd::Command;
use hmac::{Hmac, Mac};
use loomweave_core::{
LEAF_SUMMARY_PROMPT_TEMPLATE_ID,
plugin::{ContentLengthCeiling, Frame, read_frame, write_frame},
};
use loomweave_core::plugin::{ContentLengthCeiling, Frame, read_frame, write_frame};
use loomweave_llm::LEAF_SUMMARY_PROMPT_TEMPLATE_ID;
use rusqlite::{Connection, params};
use serde::Deserialize;
use serde_json::Value;
Expand Down
5 changes: 1 addition & 4 deletions crates/loomweave-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "loomweave-core"
description = "Loomweave core: entity-ID assembler, sandboxed JSON-RPC plugin host, manifest parser, and LLM/embedding provider traits."
description = "Loomweave core: entity-ID assembler, sandboxed JSON-RPC plugin host, and manifest parser."
version.workspace = true
edition.workspace = true
license.workspace = true
Expand All @@ -11,9 +11,6 @@ rust-version.workspace = true
workspace = true

[dependencies]
async-trait.workspace = true
fs2.workspace = true
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
tempfile.workspace = true
Expand Down
16 changes: 1 addition & 15 deletions crates/loomweave-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,20 @@
//! loomweave-core — domain types, identifiers, and provider traits.
//! loomweave-core — domain types, identifiers, and the sandboxed plugin host.
//!
//! # Re-export policy (ticket clarion-29acbcd042)
//!
//! Only facade types that external callers need are re-exported at the crate
//! root. Implementation types (`Frame`, `TransportError`, `RequestEnvelope`, etc.)
//! remain accessible via `loomweave_core::plugin::transport::*` and siblings.

pub mod embedding_provider;
pub mod entity_id;
pub mod errors;
pub mod hardened_git;
pub mod llm_provider;
pub mod plugin;
pub mod store;

pub use embedding_provider::{
ApiEmbeddingProvider, ApiEmbeddingProviderConfig, EmbeddingProvider, EmbeddingProviderError,
EmbeddingRecording, RecordingEmbeddingProvider,
};
pub use entity_id::{EntityId, EntityIdError, entity_id};
pub use errors::{HttpErrorCode, McpErrorCode};
pub use hardened_git::{hardened_git_command, list_untracked_files};
pub use llm_provider::{
CachingModel, ClaudeCliProvider, ClaudeCliProviderConfig, CodexCliProvider,
CodexCliProviderConfig, INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput,
LEAF_SUMMARY_PROMPT_TEMPLATE_ID, LeafSummaryPromptInput, LlmProvider, LlmProviderError,
LlmPurpose, LlmRequest, LlmResponse, OpenRouterProvider, OpenRouterProviderConfig,
PromptTemplate, Recording, RecordingProvider, TrafficLoggingProvider,
build_coding_agent_provider_prompt, build_inferred_calls_prompt, build_leaf_summary_prompt,
};
pub use plugin::{
// host (Task 6) — facade for callers that spawn/connect plugins
AcceptedEdge,
Expand Down
23 changes: 23 additions & 0 deletions crates/loomweave-llm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "loomweave-llm"
description = "Loomweave LLM + embedding provider traits, concrete providers (OpenRouter / Codex CLI / Claude CLI), and the outbound HTTP/CLI transport for summaries and embeddings."
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[lints]
workspace = true

[dependencies]
async-trait.workspace = true
fs2.workspace = true
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
tempfile.workspace = true
thiserror.workspace = true
tokio.workspace = true
tracing.workspace = true
which.workspace = true
21 changes: 21 additions & 0 deletions crates/loomweave-llm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! loomweave-llm — LLM + embedding provider traits, concrete providers, and the
//! outbound HTTP/CLI transport for Loomweave summaries and embeddings.
//!
//! Extracted from `loomweave-core` (PRD-0001, clarion-141e9c08c8) so the
//! plugin-supervisor + SEI crate does not link an outbound HTTP client.

pub mod embedding_provider;
pub mod llm_provider;

pub use embedding_provider::{
ApiEmbeddingProvider, ApiEmbeddingProviderConfig, EmbeddingProvider, EmbeddingProviderError,
EmbeddingRecording, RecordingEmbeddingProvider,
};
pub use llm_provider::{
CachingModel, ClaudeCliProvider, ClaudeCliProviderConfig, CodexCliProvider,
CodexCliProviderConfig, INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput,
LEAF_SUMMARY_PROMPT_TEMPLATE_ID, LeafSummaryPromptInput, LlmProvider, LlmProviderError,
LlmPurpose, LlmRequest, LlmResponse, OpenRouterProvider, OpenRouterProviderConfig,
PromptTemplate, Recording, RecordingProvider, TrafficLoggingProvider,
build_coding_agent_provider_prompt, build_inferred_calls_prompt, build_leaf_summary_prompt,
};
1 change: 1 addition & 0 deletions crates/loomweave-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ workspace = true
async-trait.workspace = true
blake3.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-llm = { path = "../loomweave-llm", version = "1.3.1" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Publish loomweave-llm before dependent crates

On a tagged release, this new versioned dependency has to resolve from crates.io after Cargo strips the local path, but I checked the publish-crates job in .github/workflows/release.yml:512-519 and it publishes core/scanner/analysis/storage/federation/plugin-rust/mcp/cli without ever publishing loomweave-llm. The first release containing this split will therefore fail when publishing loomweave-mcp (and then loomweave-cli); add publish loomweave-llm before the dependent crates in that workflow.

Useful? React with 👍 / 👎.

loomweave-federation = { path = "../loomweave-federation", version = "1.3.1" }
loomweave-storage = { path = "../loomweave-storage", version = "1.3.1" }
reqwest.workspace = true
Expand Down
8 changes: 3 additions & 5 deletions crates/loomweave-mcp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ use std::collections::{BTreeSet, HashMap};
use std::path::{Component, Path, PathBuf};
use std::sync::{Arc, Mutex};

use loomweave_core::{
EdgeConfidence, EmbeddingProvider, LlmProvider, LlmProviderError, LlmRequest, LlmResponse,
McpErrorCode,
};
use loomweave_core::{EdgeConfidence, McpErrorCode};
use loomweave_llm::{EmbeddingProvider, LlmProvider, LlmProviderError, LlmRequest, LlmResponse};
use rusqlite::{Connection, OpenFlags, OptionalExtension};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -6128,7 +6126,7 @@ mod tests {
use std::sync::Arc;
use std::time::Duration;

use loomweave_core::{CachingModel, LlmProvider, LlmProviderError, LlmRequest, LlmResponse};
use loomweave_llm::{CachingModel, LlmProvider, LlmProviderError, LlmRequest, LlmResponse};
use loomweave_storage::{
EntityRow, InferredEdgeCacheKey, ReaderPool, UnresolvedCallSiteRow, pragma, schema,
};
Expand Down
3 changes: 2 additions & 1 deletion crates/loomweave-mcp/src/tools/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

use std::collections::HashMap;

use loomweave_core::{LeafSummaryPromptInput, McpErrorCode, build_leaf_summary_prompt};
use loomweave_core::McpErrorCode;
use loomweave_llm::{LeafSummaryPromptInput, build_leaf_summary_prompt};
use serde_json::{Value, json};

use loomweave_storage::{
Expand Down
9 changes: 5 additions & 4 deletions crates/loomweave-mcp/src/tools/summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ use std::collections::HashSet;
use std::path::Path;
use std::sync::Arc;

use loomweave_core::{
EdgeConfidence, INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput,
LEAF_SUMMARY_PROMPT_TEMPLATE_ID, LeafSummaryPromptInput, LlmPurpose, LlmRequest, McpErrorCode,
build_inferred_calls_prompt, build_leaf_summary_prompt,
use loomweave_core::{EdgeConfidence, McpErrorCode};
use loomweave_llm::{
INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput, LEAF_SUMMARY_PROMPT_TEMPLATE_ID,
LeafSummaryPromptInput, LlmPurpose, LlmRequest, build_inferred_calls_prompt,
build_leaf_summary_prompt,
};
use serde_json::{Value, json};
use tokio::sync::{broadcast, mpsc, oneshot};
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-mcp/tests/catalogue_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use loomweave_core::{EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_llm::{EmbeddingRecording, RecordingEmbeddingProvider};
use loomweave_mcp::config::SemanticSearchConfig;
use loomweave_mcp::filigree::{
EntityAssociationsResponse, FiligreeClientError, FiligreeLookup, WardlineFinding,
Expand Down
12 changes: 6 additions & 6 deletions crates/loomweave-mcp/tests/storage_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ use std::{
},
};

use loomweave_core::{
CachingModel, INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput,
LEAF_SUMMARY_PROMPT_TEMPLATE_ID, LeafSummaryPromptInput, LlmProvider, LlmProviderError,
LlmPurpose, LlmRequest, LlmResponse, OpenRouterProvider, OpenRouterProviderConfig, Recording,
RecordingProvider, build_inferred_calls_prompt, build_leaf_summary_prompt,
};
use loomweave_federation::{
loomweave_port::publish_port,
loomweave_url::{
SOURCE_EPHEMERAL_PORT as LOOMWEAVE_SOURCE_EPHEMERAL_PORT,
SOURCE_NONE as LOOMWEAVE_SOURCE_NONE,
},
};
use loomweave_llm::{
CachingModel, INFERRED_CALLS_PROMPT_VERSION, InferredCallsPromptInput,
LEAF_SUMMARY_PROMPT_TEMPLATE_ID, LeafSummaryPromptInput, LlmProvider, LlmProviderError,
LlmPurpose, LlmRequest, LlmResponse, OpenRouterProvider, OpenRouterProviderConfig, Recording,
RecordingProvider, build_inferred_calls_prompt, build_leaf_summary_prompt,
};
use loomweave_mcp::{
DiagnosticsContext, LlmDiagnostics, McpToolPolicy, ServerState,
config::{FiligreeConfig, LlmConfig, LlmProviderKind},
Expand Down
10 changes: 9 additions & 1 deletion site/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const quickStart =
<EnrichmentChip client:visible state="present" peer="wardline" />
<EnrichmentChip client:visible state="present" peer="warpline" />
<EnrichmentChip client:visible state="absent" peer="legis" />
<EnrichmentChip client:visible state="unavailable" peer="charter" />
<EnrichmentChip client:visible state="unavailable" peer="plainweave" />
</div>
</div>
</div>
Expand Down Expand Up @@ -338,6 +338,14 @@ const quickStart =
</ul>
</Banner>

<Banner client:visible tone="danger" title="Not a security scanner — SEI is identity, not authorization.">
Loomweave maps structure and mints identity; it does not scan for
vulnerabilities, render a SAST verdict, or decide who may touch what. The
<code>SEI</code> is a stable coordinate, not a credential — keying a fact on it
grants no authority. Loomweave is deconfliction-first, not security; never treat
its structural graph or its identities as an access-control or compliance boundary.
</Banner>

<ul class="spine__notes">
{SEI_SPINE.facts.map((fact) => <li>{fact}</li>)}
</ul>
Expand Down