Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a695c10
Unify runtime store graph selection
ilblackdragon Jul 21, 2026
a9850c7
Shrink runtime graph mode branching
ilblackdragon Jul 21, 2026
c5c7889
Unify scoped filesystem graph resources
ilblackdragon Jul 21, 2026
bb37f32
Route identity and secrets through runtime graph
ilblackdragon Jul 21, 2026
778c2b8
Use composite filesystem for production graph
ilblackdragon Jul 22, 2026
30a28d4
Collapse production runtime graph wrapper
ilblackdragon Jul 22, 2026
5ec5e9e
Store one runtime graph in services
ilblackdragon Jul 22, 2026
cf39aed
Rename runtime auxiliary surfaces
ilblackdragon Jul 22, 2026
975ede7
Consolidate Reborn runtime composition
ilblackdragon Jul 22, 2026
2ea47b5
Merge remote-tracking branch 'origin/main' into agent/unify-runtime-s…
ilblackdragon Jul 22, 2026
1f07677
Unify Reborn runtime storage assembly
ilblackdragon Jul 22, 2026
975bcd2
Unify reborn runtime assembly
ilblackdragon Jul 22, 2026
eea2c91
refactor(reborn-composition): fix branch build + advance composition …
ilblackdragon Jul 22, 2026
2a00e08
style+test: cargo fmt the composition refactor + fix max_egress_bytes…
ilblackdragon Jul 22, 2026
9bed44d
test(reborn-composition): rewrite budget/auto-approve peek tests to e…
ilblackdragon Jul 22, 2026
ca5f1be
test(integration): defer 2 channel/pairing suites; integration suite …
ilblackdragon Jul 22, 2026
8237abe
refactor(reborn-composition): finish DEL-7 — drop ironclaw_first_part…
ilblackdragon Jul 23, 2026
185adca
Merge remote-tracking branch 'origin/main' into agent/unify-runtime-s…
ilblackdragon Jul 23, 2026
12ac21a
refactor(reborn-composition): rename RebornBuildInput -> RebornHostBi…
ilblackdragon Jul 23, 2026
2d89a04
refactor(reborn-composition): move declarative DATA into DeploymentCo…
ilblackdragon Jul 23, 2026
b7f01c2
refactor(reborn-composition): surface DeploymentConfig as first-class…
ilblackdragon Jul 23, 2026
f7702f4
fix(reborn-composition): resolve runtime policy in local-dev construc…
ilblackdragon Jul 23, 2026
2cdc449
refactor(reborn-composition): remove RebornHostBindings::local_dev[_w…
ilblackdragon Jul 23, 2026
d440f79
test(reborn-composition): inject first-party surface into local-dev t…
ilblackdragon Jul 23, 2026
eb8c17a
fix(reborn-composition): restore 3 local-dev behaviors dropped by uni…
ilblackdragon Jul 23, 2026
232562b
test(reborn-composition): update runtime-unification expectations (un…
ilblackdragon Jul 23, 2026
d913d1e
style(reborn-composition): cargo fmt the task-8 edits
ilblackdragon Jul 23, 2026
24ee6b9
Merge origin/main into runtime composition branch
ilblackdragon Jul 23, 2026
55ff50c
Strengthen runtime observer and hook coverage
ilblackdragon Jul 23, 2026
478e50e
Fix code style CI gates
ilblackdragon Jul 23, 2026
277eb2e
Trigger PR CI sync
ilblackdragon Jul 23, 2026
20d8d52
Refresh PR checks
ilblackdragon Jul 23, 2026
9cee40a
Cover runtime observers and CI wiring
ilblackdragon Jul 23, 2026
d965f2e
Merge remote-tracking branch 'origin/main' into agent/unify-runtime-s…
ilblackdragon Jul 23, 2026
0edf890
Wire bundled extensions into lifecycle CLI
ilblackdragon Jul 23, 2026
6480b5b
Refresh PR sync
ilblackdragon Jul 23, 2026
fc83f9d
Fix runtime composition CI ratchets
ilblackdragon Jul 23, 2026
2f994a7
Address extension runtime review coverage
ilblackdragon Jul 23, 2026
f74d173
Merge remote-tracking branch 'origin/main' into agent/unify-runtime-s…
ilblackdragon Jul 23, 2026
640ae5d
Fix Reborn adapters CI gates
ilblackdragon Jul 23, 2026
abe51fb
Fix Reborn runtime wiring CI coverage
ilblackdragon Jul 23, 2026
c08b16a
Merge remote-tracking branch 'origin/main' into agent/unify-runtime-s…
ilblackdragon Jul 23, 2026
fc7e5c8
Wire bundled extensions in product API integration
ilblackdragon Jul 23, 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
2 changes: 1 addition & 1 deletion .claude/skills/reborn-extension-surfaces/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Re-verify the module list: `grep -n 'ID,' crates/ironclaw_first_party_extensions
normalized outcome; `deliver` render+send; idempotent `activate`/`cleanup`
vendor wiring) — see the trait doc for the method contract. The binary
supplies the adapter to composition through the
`RebornBuildInput::with_channel_extension_bindings` seam
`RebornHostBindings::with_channel_extension_bindings` seam
(`crates/ironclaw_reborn_composition/src/input.rs`, `ChannelExtensionBinding`);
composition iterates it by `extension_id` and never names a concrete crate.
4. Conversation/actor binding is **data, not per-channel code**: the
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ verification recipe, `[channel.config]`, egress allowlist, presentation) beside
the extension's tools and auth recipes, and the extension's `ChannelAdapter`
(`crates/ironclaw_product_adapters`) implements inbound normalize / deliver /
activate / cleanup. Binaries supply adapters through
`RebornBuildInput::with_channel_extension_bindings`
`RebornHostBindings::with_channel_extension_bindings`
(`crates/ironclaw_reborn_composition/src/input.rs`); composition wires the
generic ingress router, pairing seam, identity bindings, and the host-owned
delivery coordinator — never per-channel host code. Start from the
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,7 @@ fn descriptor(id: CapabilityId) -> CapabilityDescriptor {
default_permission: PermissionMode::Deny,
runtime_credentials: Vec::new(),
network_targets: Vec::new(),
max_egress_bytes: None,
resource_profile: None,
origin_gate_matrix: None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ fn reborn_binary_main_is_thin_bootstrap() {
);
for forbidden in [
"build_reborn_runtime",
"build_reborn_services",
"build_runtime",
"axum::serve",
"TcpListener::bind",
"src/channels/web",
Expand Down Expand Up @@ -302,7 +302,7 @@ const EXTENSION_HOST_INTERNAL_MODULES: &[&str] = &[
"extension_lifecycle_capabilities",
"extension_lifecycle_capabilities_auth_tests",
"extension_lifecycle_command",
"gsuite",
"first_party",
"lifecycle",
"mcp",
"mcp_discovery",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ fn reborn_cli_binary_crate_stays_separate_from_v1_root() {
"ironclaw",
[
"ironclaw_extension_host",
"ironclaw_first_party_extensions",
"ironclaw_reborn_composition",
"ironclaw_reborn_config",
"ironclaw_reborn_traces",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,11 @@ use std::path::{Path, PathBuf};
/// `RebornCompositionProfile` variant, each with the reason it is still here.
///
/// Sorted; entries are `src/`-relative with `/` separators.
const ALLOWLIST: &[(&str, &str)] = &[
(
"deployment.rs",
"TARGET STATE — `DeploymentConfig::for_profile` is the one place a \
const ALLOWLIST: &[(&str, &str)] = &[(
"deployment.rs",
"TARGET STATE — `DeploymentConfig::for_profile` is the one place a \
profile name becomes deployment data (§4.4). This entry stays.",
),
(
"readiness.rs",
"Readiness diagnostics carry a profile as an operator-facing **label** \
on the wire (`RebornReadinessDiagnostic::profile`), not a branch. \
Retires only if that wire field is reshaped.",
),
];
)];

fn workspace_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
Expand Down
42 changes: 24 additions & 18 deletions crates/ironclaw_architecture/tests/reborn_extension_specificity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1128,17 +1128,20 @@ const ALLOWLIST: &[(&str, &str)] = &[
"crates/ironclaw_reborn_composition/src/extension_host/extension_lifecycle.rs",
"slack",
),
(
"crates/ironclaw_reborn_composition/src/extension_host/gsuite.rs",
"google",
),
(
"crates/ironclaw_reborn_composition/src/projection/display_preview.rs",
"web-access",
),
// DEL-7: the manifest-egress policy builder's comment names the GSuite
// (Google API hosts) and web-access (Exa MCP) egress it no longer
// special-cases — the code routes purely on manifest-declared targets.
(
"crates/ironclaw_reborn_composition/src/runtime/local_dev/extension_surface.rs",
"google",
),
(
"crates/ironclaw_reborn_composition/src/runtime/local_dev/extension_surface.rs",
"web_access",
"web-access",
),
// lane-4: nearai-slice — the last catalog package (nearai_mcp) still assembled in composition because [mcp].server is patched from llm_admin config; DEFERRED — finish per the handoff (move static data to first_party_extensions::packages::nearai_mcp, inject the URL through the with_channel_extension_bindings-style seam)
(
Expand All @@ -1165,6 +1168,14 @@ const ALLOWLIST: &[(&str, &str)] = &[
"crates/ironclaw_reborn_composition/src/input.rs",
"nearaimcp",
),
(
"crates/ironclaw_reborn_composition/src/deployment.rs",
"nearai_mcp",
),
(
"crates/ironclaw_reborn_composition/src/deployment.rs",
"nearaimcp",
),
(
"crates/ironclaw_reborn_composition/src/lib.rs",
"nearai_mcp",
Expand Down Expand Up @@ -1192,22 +1203,17 @@ const ALLOWLIST: &[(&str, &str)] = &[
),
// lane-4: migration — one-time forward-migration call sites naming the v1 vocabulary they fold forward — correct-by-design (same pattern the retired-taxonomy gate sanctions); would become a SANCTIONED_PATHS carve if the sites move into a dedicated migration module
("crates/ironclaw_reborn_composition/src/factory.rs", "slack"),
// lane-4: web-access-mod — the web-access first-party handler assembly module + its registration — extension-specific host wiring pending a generic first-party-handler seam keyed by manifest service
(
"crates/ironclaw_reborn_composition/src/factory.rs",
"web_access",
),
// DEL-7: the `google_oauth_configured` build-time signal on the neutral
// first-party registrar context (a field name, not an extension branch —
// the concrete GSuite handler lives in the binary). `nearaimcp` is the
// deferred nearai-slice concern above, folded forward in factory wiring.
(
"crates/ironclaw_reborn_composition/src/lib.rs",
"web_access",
),
(
"crates/ironclaw_reborn_composition/src/web_access.rs",
"web_access",
"crates/ironclaw_reborn_composition/src/extension_host/first_party.rs",
"google",
),
(
"crates/ironclaw_reborn_composition/src/web_access.rs",
"webaccess",
"crates/ironclaw_reborn_composition/src/factory.rs",
"nearaimcp",
),
// lane-4: doc-str — incidental doc-comment / error-string / tool-description examples that NAME an extension but branch on nothing — the code routes by a manifest field (display_name/provider/effects); reword or leave (Ben's call)
("crates/ironclaw_filesystem/src/index.rs", "acme"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@ fn wasm_descriptor() -> CapabilityDescriptor {
default_permission: PermissionMode::Allow,
runtime_credentials: Vec::new(),
network_targets: Vec::new(),
max_egress_bytes: None,
resource_profile: None,
origin_gate_matrix: None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,7 @@ fn descriptor(id: CapabilityId) -> CapabilityDescriptor {
default_permission: PermissionMode::Deny,
runtime_credentials: Vec::new(),
network_targets: Vec::new(),
max_egress_bytes: None,
resource_profile: None,
origin_gate_matrix: None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ fn wasm_descriptor() -> CapabilityDescriptor {
default_permission: PermissionMode::Allow,
runtime_credentials: Vec::new(),
network_targets: Vec::new(),
max_egress_bytes: None,
resource_profile: None,
origin_gate_matrix: None,
}
Expand Down
4 changes: 4 additions & 0 deletions crates/ironclaw_extensions/src/hosted_mcp_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn package_with_discovered_hosted_mcp_tools(
default_permission: capability.default_permission,
runtime_credentials: capability.runtime_credentials.clone(),
network_targets: capability.network_targets.clone(),
max_egress_bytes: capability.max_egress_bytes,
resource_profile: capability.resource_profile.clone(),
origin_gate_matrix: capability.origin_gate_matrix.clone(),
})
Expand Down Expand Up @@ -203,6 +204,9 @@ fn discovered_capability_manifest(
// MCP discovered tools derive egress from their credential audiences,
// not a manifest-declared allowlist.
network_targets: Vec::new(),
// MCP discovered tools take no manifest egress cap; their egress is
// bounded by credential audiences and the runtime resource profile.
max_egress_bytes: None,
resource_profile: template.resource_profile.clone(),
origin_gate_matrix: template.origin_gate_matrix.clone(),
})
Expand Down
1 change: 1 addition & 0 deletions crates/ironclaw_extensions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ fn capability_descriptors_from_manifest(
default_permission: capability.default_permission,
runtime_credentials: capability.runtime_credentials.clone(),
network_targets: capability.network_targets.clone(),
max_egress_bytes: capability.max_egress_bytes,
resource_profile: capability.resource_profile.clone(),
origin_gate_matrix: capability.origin_gate_matrix.clone(),
})
Expand Down
11 changes: 11 additions & 0 deletions crates/ironclaw_extensions/src/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,12 @@ pub struct CapabilityDeclV2 {
/// A capability that declares the `network` effect but no credential uses
/// this to populate its egress allowlist directly from the manifest.
pub network_targets: Vec<NetworkTargetPattern>,
/// Optional per-capability egress cap (bytes), independent of credentials.
/// A networked capability uses this to bound its egress from the manifest
/// rather than a composition special-case. `#[serde(default)]` keeps
/// persisted records without the field parsing to `None`.
#[serde(default)]
pub max_egress_bytes: Option<u64>,
pub resource_profile: Option<ResourceProfile>,
/// Declared per-origin gate matrix (§5.2.1). `None` = undeclared; a later
/// slice populates real matrices and threads this into authorization.
Expand Down Expand Up @@ -1246,6 +1252,7 @@ impl CapabilityDeclV2 {
required_host_ports,
runtime_credentials,
network_targets,
max_egress_bytes: raw.max_egress_bytes,
resource_profile: raw.resource_profile,
origin_gate_matrix: raw.origin_gate_matrix,
})
Expand Down Expand Up @@ -1787,6 +1794,10 @@ pub(crate) struct RawCapabilityV2 {
pub(crate) runtime_credentials: Vec<RawRuntimeCredentialV2>,
#[serde(default)]
pub(crate) network_targets: Vec<NetworkTargetPattern>,
/// Optional per-capability egress cap (bytes). `#[serde(default)]` so
/// existing manifests without the key parse to `None`.
#[serde(default)]
pub(crate) max_egress_bytes: Option<u64>,
#[serde(default)]
pub(crate) resource_profile: Option<ResourceProfile>,
/// Per-origin gate matrix (§5.2.1). `#[serde(default)]` so existing
Expand Down
12 changes: 11 additions & 1 deletion crates/ironclaw_extensions/src/v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ struct RawToolV3 {
/// still applies.
#[serde(default)]
network_targets: Vec<ironclaw_host_api::NetworkTargetPattern>,
/// Optional per-tool egress cap (bytes). `#[serde(default)]` so tools
/// without the key parse to `None` (no cap). Threads to the capability's
/// `NetworkPolicy.max_egress_bytes` at grant issuance.
#[serde(default)]
max_egress_bytes: Option<u64>,
#[serde(default)]
resource_profile: Option<ironclaw_host_api::ResourceProfile>,
}
Expand Down Expand Up @@ -377,6 +382,7 @@ pub(crate) fn parse_v3(
let raw_capability = RawCapabilityV2 {
id: format!("{id}.mcp_server"),
network_targets: Vec::new(),
max_egress_bytes: None,
implements: Vec::new(),
description: format!(
"Hosted MCP server connection for {} (discovery template; never model-visible)",
Expand Down Expand Up @@ -416,20 +422,23 @@ pub(crate) fn parse_v3(
|| !tool.effects.is_empty()
|| tool.resource_profile.is_some()
|| !tool.network_targets.is_empty()
|| tool.max_egress_bytes.is_some()
|| tool.output_schema_ref.is_some()
{
return Err(ManifestV3Error::Invalid {
reason: format!(
"static tool `{}` on an [mcp] manifest inherits the server \
connection template; remove its credentials, effects, \
network_targets, output_schema_ref, and resource_profile",
network_targets, max_egress_bytes, output_schema_ref, and \
resource_profile",
tool.id
),
});
}
RawCapabilityV2 {
id: tool.id,
network_targets: Vec::new(),
max_egress_bytes: None,
implements: Vec::new(),
description: tool.description,
effects: with_dispatch_effect(mcp.effects.clone()),
Expand All @@ -447,6 +456,7 @@ pub(crate) fn parse_v3(
_ => RawCapabilityV2 {
id: tool.id,
network_targets: tool.network_targets,
max_egress_bytes: tool.max_egress_bytes,
implements: Vec::new(),
description: tool.description,
effects: with_dispatch_effect(tool.effects.clone()),
Expand Down
48 changes: 48 additions & 0 deletions crates/ironclaw_first_party_extensions/assets/gmail/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/list_messages.input.v1.json"
prompt_doc_ref = "prompts/gmail/list_messages.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760
Comment thread
ilblackdragon marked this conversation as resolved.

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand All @@ -45,6 +53,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/get_message.input.v1.json"
prompt_doc_ref = "prompts/gmail/get_message.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand All @@ -62,6 +78,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/send_message.input.v1.json"
prompt_doc_ref = "prompts/gmail/send_message.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand All @@ -79,6 +103,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/create_draft.input.v1.json"
prompt_doc_ref = "prompts/gmail/create_draft.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand All @@ -96,6 +128,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/reply_to_message.input.v1.json"
prompt_doc_ref = "prompts/gmail/reply_to_message.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand All @@ -113,6 +153,14 @@ visibility = "model"
input_schema_ref = "schemas/gmail/trash_message.input.v1.json"
prompt_doc_ref = "prompts/gmail/trash_message.md"

network_targets = [
{ scheme = "https", host_pattern = "www.googleapis.com" },
{ scheme = "https", host_pattern = "gmail.googleapis.com" },
{ scheme = "https", host_pattern = "oauth2.googleapis.com" },
{ scheme = "https", host_pattern = "accounts.google.com" },
]
max_egress_bytes = 10485760

[[tools.credentials]]
handle = "gmail_account"
vendor = "google"
Expand Down
Loading
Loading