Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ba9299d
Add public agent start scope and capability flags
May 27, 2026
695e72a
Implement public world-scoped agent start capability flags
May 27, 2026
60b779c
Enable world-scope public agent start with deferred attach
May 27, 2026
2e7414c
Update commit message generation for diff context
May 27, 2026
dfb3b1e
Refine commit message generation for diff context
May 27, 2026
22e956f
Update commit message generation
May 27, 2026
c8c5f88
Refine commit message generation instructions
May 27, 2026
680b2f1
Refine slice 30 docs for host-first start semantics
May 27, 2026
a76706c
Fix agent start world attachment semantics
May 27, 2026
663b927
Update repository guidance for substrate workflows
May 27, 2026
d3bfd07
Update repository instructions
May 27, 2026
9d35a5c
Refine slice 30 packet 3 world binding contract
May 27, 2026
25d365d
fix: enforce authoritative parent world binding reuse
May 27, 2026
460f4f1
docs: finalize slice 30 packet 4 planning
May 28, 2026
9f6af19
fix: close slice 30 packet 4
May 28, 2026
3b59a7b
docs: reopen packet 4 closeout truthfully
May 28, 2026
9c703d6
docs: close slice 30 packet 4 honestly
May 28, 2026
e3eb273
fix: add fresh install gateway smoke helper
May 28, 2026
5f82fc8
Fix macOS shell clippy and preflight tests
Spenquatch May 28, 2026
cbebdb3
patch: add missing imports for Linux target in agents_cmd.rs
Spenquatch May 28, 2026
5b2f6ca
patch: add .codex-turn-capture to .gitignore
Spenquatch May 28, 2026
0980b8c
Add TASKS for runtime family alias support
May 28, 2026
2c5edb5
Add typed runtime family inventory support
May 28, 2026
c4664f4
Resolve shell UAA runtime family from inventory truth
May 28, 2026
17b7b36
Fix packet 3 alias runtime family fixtures and routing tests
May 28, 2026
605e853
Document gitnexus CLI workflow for packet 4
May 28, 2026
1da45b4
Document runtime family alias fixtures and docs
May 28, 2026
a70ef15
Add runtime family support to agent file configurations
Spenquatch May 28, 2026
06fe32c
fix: gate unix-only shell compile paths
Spenquatch May 28, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ wt/
__pycache__/
*.pyc
.runs
.codex-turn-capture

# Triad/Codex artifacts (store under feature planning packs to survive `cargo clean`)
docs/project_management/next/**/logs/
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ cargo bench # exercise hotspots when touching pe
<!-- gitnexus:start -->
# GitNexus — Code Intelligence

This project is indexed by GitNexus as **substrate** (49749 symbols, 77069 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
This project is indexed by GitNexus as **substrate** (25015 symbols, 50288 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.

> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- gitnexus:start -->
# GitNexus — Code Intelligence

This project is indexed by GitNexus as **substrate** (49749 symbols, 77069 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
This project is indexed by GitNexus as **substrate** (25015 symbols, 50288 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.

> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

Expand Down
64 changes: 61 additions & 3 deletions crates/shell/src/execution/agent_inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,22 @@ pub(crate) struct AgentExecutionConfigV1 {
pub scope: Option<crate::execution::config_model::AgentExecutionScope>,
}

#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum AgentCliRuntimeFamily {
Codex,
ClaudeCode,
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub(crate) struct AgentCliConfigV1 {
#[serde(default)]
pub binary: String,
#[serde(default)]
pub mode: Option<crate::execution::config_model::AgentCliMode>,
#[serde(default)]
pub runtime_family: Option<AgentCliRuntimeFamily>,
}

#[derive(Debug, Clone, Deserialize)]
Expand Down Expand Up @@ -127,6 +136,7 @@ pub(crate) struct ProjectedInventoryEntryV1 {
pub cli_mode: crate::execution::config_model::AgentCliMode,
pub cli_mode_origin: ProjectedInventoryValueOrigin,
pub cli_binary: Option<String>,
pub cli_runtime_family: Option<AgentCliRuntimeFamily>,
pub capabilities: AgentCapabilitiesV1,
#[allow(dead_code)]
pub policy_overlay: Option<crate::execution::policy_model::PolicyPatch>,
Expand Down Expand Up @@ -167,6 +177,10 @@ impl AgentFileV1 {
Some(trimmed)
}
}

pub(crate) fn cli_runtime_family(&self) -> Option<AgentCliRuntimeFamily> {
self.config.cli.as_ref().and_then(|cli| cli.runtime_family)
}
}

impl AgentInventoryEntryV1 {
Expand All @@ -191,6 +205,10 @@ impl AgentInventoryEntryV1 {
pub(crate) fn effective_cli_binary(&self) -> Option<&str> {
self.file.effective_cli_binary()
}

pub(crate) fn cli_runtime_family(&self) -> Option<AgentCliRuntimeFamily> {
self.file.cli_runtime_family()
}
}

pub(crate) fn inventory_entry_origin(
Expand Down Expand Up @@ -274,6 +292,7 @@ pub(crate) fn project_inventory_entry(
cli_mode: entry.effective_cli_mode(effective_config),
cli_mode_origin,
cli_binary: entry.effective_cli_binary().map(ToOwned::to_owned),
cli_runtime_family: entry.cli_runtime_family(),
capabilities: entry.file.config.capabilities.clone(),
policy_overlay: entry.file.policy_overlay.clone(),
}
Expand Down Expand Up @@ -532,6 +551,7 @@ fn validate_agent_config(path: &Path, config: &AgentConfigV1) -> Result<()> {
let _ = &config.protocol;
let _ = config.execution.scope;
let _ = config.cli.as_ref().and_then(|cli| cli.mode);
let _ = config.cli.as_ref().and_then(|cli| cli.runtime_family);
let _ = config.enabled;
let _ = config.capabilities.session_start;
let _ = config.capabilities.session_resume;
Expand Down Expand Up @@ -832,10 +852,11 @@ fn validate_overlay_subset(
#[cfg(test)]
mod tests {
use super::{
inventory_entry_origin, AgentCapabilitiesV1, AgentCliConfigV1, AgentConfigKind,
AgentConfigV1, AgentExecutionConfigV1, AgentFileV1, AgentInventoryBaselineOrigin,
AgentInventoryEntryV1,
inventory_entry_origin, project_inventory_entry, AgentCapabilitiesV1, AgentCliConfigV1,
AgentCliRuntimeFamily, AgentConfigKind, AgentConfigV1, AgentExecutionConfigV1, AgentFileV1,
AgentInventoryBaselineOrigin, AgentInventoryEntryV1,
};
use crate::execution::config_model::{AgentCliMode, SubstrateConfig};
use crate::execution::workspace::{workspace_marker_path, SUBSTRATE_DIR_NAME};
use tempfile::tempdir;

Expand Down Expand Up @@ -863,6 +884,7 @@ mod tests {
cli: Some(AgentCliConfigV1 {
binary: "codex".to_string(),
mode: None,
runtime_family: None,
}),
api: None,
capabilities: AgentCapabilitiesV1::default(),
Expand All @@ -876,4 +898,40 @@ mod tests {
AgentInventoryBaselineOrigin::WorkspaceInventory
);
}

#[test]
fn project_inventory_entry_carries_cli_runtime_family_truth() {
let cwd = tempdir().expect("tempdir");
let mut effective_config = SubstrateConfig::default();
effective_config.agents.defaults.cli.mode = AgentCliMode::Persistent;

let entry = AgentInventoryEntryV1 {
path: cwd.path().join("codex_world.yaml"),
file: AgentFileV1 {
version: 1,
id: "codex_world".to_string(),
config: AgentConfigV1 {
enabled: true,
kind: AgentConfigKind::Cli,
protocol: Some("substrate.agent.session".to_string()),
execution: AgentExecutionConfigV1::default(),
cli: Some(AgentCliConfigV1 {
binary: "codex".to_string(),
mode: None,
runtime_family: Some(AgentCliRuntimeFamily::Codex),
}),
api: None,
capabilities: AgentCapabilitiesV1::default(),
},
policy_overlay: None,
},
};

let projected = project_inventory_entry(cwd.path(), &entry, &effective_config);

assert_eq!(
projected.cli_runtime_family,
Some(AgentCliRuntimeFamily::Codex)
);
}
}
48 changes: 40 additions & 8 deletions crates/shell/src/execution/agent_runtime/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,22 +576,40 @@ where
}

#[cfg(unix)]
pub(crate) fn run_hidden_owner_helper_startup_prompt_stream(
pub(crate) fn run_hidden_owner_helper_startup_prompt_stream_with_action(
listener: StartupPromptTransportListener,
json: bool,
action: PublicPromptAction,
) -> Result<()> {
run_hidden_owner_helper_startup_prompt_stream_with_projection(
listener, json, action, None, None,
)
}

#[cfg(unix)]
pub(crate) fn run_hidden_owner_helper_startup_prompt_stream_with_public_identity(
listener: StartupPromptTransportListener,
json: bool,
action: PublicPromptAction,
backend_id: &str,
scope: AgentExecutionScope,
) -> Result<()> {
run_hidden_owner_helper_startup_prompt_stream_with_action(
run_hidden_owner_helper_startup_prompt_stream_with_projection(
listener,
json,
PublicPromptAction::Start,
action,
Some(backend_id),
Some(scope),
)
}

#[cfg(unix)]
pub(crate) fn run_hidden_owner_helper_startup_prompt_stream_with_action(
fn run_hidden_owner_helper_startup_prompt_stream_with_projection(
listener: StartupPromptTransportListener,
json: bool,
action: PublicPromptAction,
backend_id_override: Option<&str>,
scope_override: Option<AgentExecutionScope>,
) -> Result<()> {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
Expand All @@ -609,7 +627,12 @@ pub(crate) fn run_hidden_owner_helper_startup_prompt_stream_with_action(
) {
saw_terminal = true;
}
let rewritten = rewrite_startup_prompt_envelope_action(envelope, action);
let rewritten = rewrite_startup_prompt_envelope_action(
envelope,
action,
backend_id_override,
scope_override,
);
renderer.render(&rewritten)
})
.await
Expand Down Expand Up @@ -640,6 +663,8 @@ pub(crate) fn run_hidden_owner_helper_startup_prompt_stream_with_action(
fn rewrite_startup_prompt_envelope_action(
envelope: &PublicPromptEnvelope,
action: PublicPromptAction,
backend_id_override: Option<&str>,
scope_override: Option<AgentExecutionScope>,
) -> PublicPromptEnvelope {
match envelope {
PublicPromptEnvelope::Accepted {
Expand All @@ -653,9 +678,14 @@ fn rewrite_startup_prompt_envelope_action(
version: *version,
action,
orchestration_session_id: orchestration_session_id.clone(),
backend_id: backend_id.clone(),
backend_id: backend_id_override
.unwrap_or(backend_id.as_str())
.to_string(),
participant_id: participant_id.clone(),
scope: scope.clone(),
scope: scope_override
.map(scope_label)
.unwrap_or(scope.as_str())
.to_string(),
},
PublicPromptEnvelope::Completed {
version,
Expand All @@ -671,7 +701,9 @@ fn rewrite_startup_prompt_envelope_action(
version: *version,
action,
orchestration_session_id: orchestration_session_id.clone(),
backend_id: backend_id.clone(),
backend_id: backend_id_override
.unwrap_or(backend_id.as_str())
.to_string(),
participant_id: participant_id.clone(),
turn_outcome: turn_outcome.clone(),
session_posture: *session_posture,
Expand Down
96 changes: 81 additions & 15 deletions crates/shell/src/execution/agent_runtime/dispatch_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::execution::config_model::{AgentCliMode, AgentExecutionScope, Substrat
use crate::execution::policy_model::{apply_policy_patch, PolicyPatch};

use super::mapping::{
orchestrator_backend_kind, protocol_validation_error, AgentRuntimeBackendKind,
protocol_validation_error, resolve_shell_owned_runtime_family, AgentRuntimeBackendKind,
PURE_AGENT_PROTOCOL,
};

Expand Down Expand Up @@ -667,15 +667,15 @@ fn resolve_inventory_projected_contract(
);
}

let backend_kind = orchestrator_backend_kind(projected.agent_id.as_str()).map_err(|err| {
DispatchResolutionError {
kind: DispatchResolutionErrorKind::BaselineIneligible,
field: "agent_id",
rejecting_layer: DispatchRejectingLayer::BaselineTruth,
reason: err
.to_string()
.replace("selected orchestrator backend", "selected runtime backend"),
}
let backend_kind = resolve_shell_owned_runtime_family(
projected.agent_id.as_str(),
projected.cli_runtime_family,
)
.map_err(|err| DispatchResolutionError {
kind: DispatchResolutionErrorKind::RuntimeUnrealizableAfterResolution,
field: "config.cli.runtime_family",
rejecting_layer: DispatchRejectingLayer::RuntimeMaterialization,
reason: err.to_string(),
})?;

Ok(ResolvedLaunchContract {
Expand Down Expand Up @@ -962,13 +962,14 @@ mod tests {

use super::{
resolve_inventory_contract_for_exact_backend, resolve_persisted_host_attach_contract,
AttachLaunchKnobs, AttachModePreference, DispatchBaselineKind, DispatchCallerKind,
DispatchCapabilityOverrideSet, DispatchRequestEnvelope, DispatchResolutionErrorKind,
FieldBaselineOrigin, FieldValueOrigin, HostExecutionClientStart,
AgentRuntimeBackendKind, AttachLaunchKnobs, AttachModePreference, DispatchBaselineKind,
DispatchCallerKind, DispatchCapabilityOverrideSet, DispatchRejectingLayer,
DispatchRequestEnvelope, DispatchResolutionErrorKind, FieldBaselineOrigin,
FieldValueOrigin, HostExecutionClientStart,
};
use crate::execution::agent_inventory::{
AgentCapabilitiesV1, AgentCliConfigV1, AgentConfigKind, AgentConfigV1,
AgentExecutionConfigV1, AgentFileV1, AgentInventoryEntryV1,
AgentCapabilitiesV1, AgentCliConfigV1, AgentCliRuntimeFamily, AgentConfigKind,
AgentConfigV1, AgentExecutionConfigV1, AgentFileV1, AgentInventoryEntryV1,
};
use crate::execution::agent_runtime::control::{
ResolvedRuntimeBackendKind, ResolvedRuntimeDescriptor,
Expand Down Expand Up @@ -1044,6 +1045,7 @@ mod tests {
cli: Some(AgentCliConfigV1 {
binary: "cargo".to_string(),
mode: cli_mode,
runtime_family: Some(AgentCliRuntimeFamily::Codex),
}),
api: None,
capabilities,
Expand Down Expand Up @@ -1128,6 +1130,62 @@ mod tests {
assert_eq!(resolved.execution_scope, AgentExecutionScope::Host);
}

#[test]
fn exact_backend_alias_resolves_canonical_runtime_family_from_inventory_truth() {
let cwd = PathBuf::from(".");
let mut inventory = BTreeMap::new();
inventory.insert(
"codex_world".to_string(),
AgentInventoryEntryV1 {
path: PathBuf::from("codex_world.yaml"),
file: AgentFileV1 {
version: 1,
id: "codex_world".to_string(),
config: AgentConfigV1 {
enabled: true,
kind: AgentConfigKind::Cli,
protocol: Some(super::PURE_AGENT_PROTOCOL.to_string()),
execution: AgentExecutionConfigV1 {
scope: Some(AgentExecutionScope::World),
},
cli: Some(AgentCliConfigV1 {
binary: "cargo".to_string(),
mode: Some(AgentCliMode::Persistent),
runtime_family: Some(AgentCliRuntimeFamily::Codex),
}),
api: None,
capabilities: required_capabilities(),
},
policy_overlay: None,
},
},
);
let policy = Policy {
agents_allowed_backends: vec!["cli:codex_world".to_string()],
..Policy::default()
};
let config = SubstrateConfig::default();

let resolved = resolve_inventory_contract_for_exact_backend(
&cwd,
&config,
&inventory,
&policy,
&exact_backend_envelope(
DispatchCallerKind::OrchestratorMemberStart,
DispatchBaselineKind::InventoryLaunch,
"cli:codex_world",
),
AgentExecutionScope::World,
)
.expect("resolution should succeed")
.expect("contract");

assert_eq!(resolved.agent_id, "codex_world");
assert_eq!(resolved.backend_id, "cli:codex_world");
assert_eq!(resolved.backend_kind, AgentRuntimeBackendKind::Codex);
}

#[test]
fn inventory_contract_merges_policy_overlay_into_effective_policy() {
let cwd = PathBuf::from(".");
Expand Down Expand Up @@ -1623,10 +1681,18 @@ mod tests {
.expect_err("override must fail closed");

assert_eq!(error.field, field);
assert_eq!(
error.rejecting_layer,
DispatchRejectingLayer::CallerContract
);
assert_eq!(
error.kind,
DispatchResolutionErrorKind::OverrideNotSupportedForCaller
);
assert_eq!(
error.reason,
"dispatch-time capability override is unsupported for this field in slice 29.5; only session_resume, session_fork, session_stop, status_snapshot, and event_stream may narrow from true to false"
);
}
}

Expand Down
Loading