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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
46 changes: 23 additions & 23 deletions .github/workflows/feature-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ jobs:
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets

- name: Build substrate + world-agent (debug)
- name: Build substrate + world-service (debug)
run: |
cargo build --bin substrate --bin substrate-shim
cargo build -p world-agent --bin world-agent
cargo build -p world-service --bin world-service

- name: Add substrate to PATH
run: echo "$GITHUB_WORKSPACE/target/debug" >> "$GITHUB_PATH"
Expand Down Expand Up @@ -239,11 +239,11 @@ jobs:
exit 1
fi

manual_sock="${RUNNER_TEMP:-/tmp}/substrate-world-agent.sock"
manual_log="${RUNNER_TEMP:-/tmp}/substrate-world-agent.log"
manual_sock="${RUNNER_TEMP:-/tmp}/substrate-world-service.sock"
manual_log="${RUNNER_TEMP:-/tmp}/substrate-world-service.log"
rm -f "${manual_sock}" "${manual_log}"

"${socket_activate}" --listen="${manual_sock}" --fdname=substrate-world-agent "$GITHUB_WORKSPACE/target/debug/world-agent" >"${manual_log}" 2>&1 &
"${socket_activate}" --listen="${manual_sock}" --fdname=substrate-world-service "$GITHUB_WORKSPACE/target/debug/world-service" >"${manual_log}" 2>&1 &
agent_pid=$!

for _ in $(seq 1 50); do
Expand All @@ -254,13 +254,13 @@ jobs:
done

if [[ ! -S "${manual_sock}" ]]; then
echo "ERROR: failed to start user-scoped world-agent socket fallback" >&2
echo "ERROR: failed to start user-scoped world-service socket fallback" >&2
[[ -f "${manual_log}" ]] && cat "${manual_log}" >&2
exit 1
fi

export SUBSTRATE_WORLD_SOCKET="${manual_sock}"
echo "Using user-scoped world-agent socket fallback: ${manual_sock}"
echo "Using user-scoped world-service socket fallback: ${manual_sock}"
fi

feature_dir="${{ inputs.feature_dir }}"
Expand Down Expand Up @@ -309,15 +309,15 @@ jobs:
echo "dir=." >> "$GITHUB_OUTPUT"
fi

- name: Provision world-agent (Linux self-hosted; WAPS)
if: startsWith(inputs.feature_dir, 'docs/project_management/packs/draft/world-deps-apt-provisioning') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/next/world-sync') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-agent-policy-snapshot') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/full-isolation-landlock-overlayfs-compat')
- name: Provision world-service (Linux self-hosted; WAPS)
if: startsWith(inputs.feature_dir, 'docs/project_management/packs/draft/world-deps-apt-provisioning') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/next/world-sync') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-service-policy-snapshot') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/full-isolation-landlock-overlayfs-compat')
working-directory: ${{ steps.checkout_dir.outputs.dir }}
run: |
set -euo pipefail
if [[ -S /run/substrate.sock && -w /run/substrate.sock ]]; then
echo "Using existing system world-agent socket"
echo "Using existing system world-service socket"
elif sudo -n true >/dev/null 2>&1; then
cargo build -p world-agent --release
cargo build -p world-service --release
scripts/linux/world-provision.sh --profile release --skip-build --sudo-noninteractive
else
echo "WARN: sudo -n unavailable on this runner; smoke will fall back to a user-scoped socket if needed" >&2
Expand All @@ -333,7 +333,7 @@ jobs:
exit 0
fi

echo "WARN: system world-agent socket unavailable; smoke will try a user-scoped socket fallback" >&2
echo "WARN: system world-service socket unavailable; smoke will try a user-scoped socket fallback" >&2
if [[ -e "${sock}" ]]; then
ls -l "${sock}" >&2 || true
stat "${sock}" >&2 || true
Expand Down Expand Up @@ -385,11 +385,11 @@ jobs:
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets

- name: Build substrate + world-agent (debug)
- name: Build substrate + world-service (debug)
working-directory: ${{ steps.checkout_dir.outputs.dir }}
run: |
cargo build --bin substrate --bin substrate-shim
cargo build -p world-agent --bin world-agent
cargo build -p world-service --bin world-service

- name: Add substrate to PATH
shell: bash
Expand Down Expand Up @@ -433,11 +433,11 @@ jobs:
exit 1
fi

manual_sock="${RUNNER_TEMP:-/tmp}/substrate-world-agent.sock"
manual_log="${RUNNER_TEMP:-/tmp}/substrate-world-agent.log"
manual_sock="${RUNNER_TEMP:-/tmp}/substrate-world-service.sock"
manual_log="${RUNNER_TEMP:-/tmp}/substrate-world-service.log"
rm -f "${manual_sock}" "${manual_log}"

"${socket_activate}" --listen="${manual_sock}" --fdname=substrate-world-agent "$PWD/target/debug/world-agent" >"${manual_log}" 2>&1 &
"${socket_activate}" --listen="${manual_sock}" --fdname=substrate-world-service "$PWD/target/debug/world-service" >"${manual_log}" 2>&1 &
agent_pid=$!

for _ in $(seq 1 50); do
Expand All @@ -448,13 +448,13 @@ jobs:
done

if [[ ! -S "${manual_sock}" ]]; then
echo "ERROR: failed to start user-scoped world-agent socket fallback" >&2
echo "ERROR: failed to start user-scoped world-service socket fallback" >&2
[[ -f "${manual_log}" ]] && cat "${manual_log}" >&2
exit 1
fi

export SUBSTRATE_WORLD_SOCKET="${manual_sock}"
echo "Using user-scoped world-agent socket fallback: ${manual_sock}"
echo "Using user-scoped world-service socket fallback: ${manual_sock}"
fi

feature_dir="${{ inputs.feature_dir }}"
Expand Down Expand Up @@ -581,7 +581,7 @@ jobs:
run: caffeinate -dimsu &

- name: Warm Lima world (macOS self-hosted; WAPS)
if: startsWith(inputs.feature_dir, 'docs/project_management/packs/draft/world-deps-apt-provisioning') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/next/world-sync') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-agent-policy-snapshot') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/full-isolation-landlock-overlayfs-compat')
if: startsWith(inputs.feature_dir, 'docs/project_management/packs/draft/world-deps-apt-provisioning') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/next/world-sync') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-service-policy-snapshot') || startsWith(inputs.feature_dir, 'docs/project_management/_archived/full-isolation-landlock-overlayfs-compat')
working-directory: ${{ steps.checkout_dir.outputs.dir }}
run: bash scripts/mac/lima-warm.sh "$PWD"

Expand Down Expand Up @@ -751,7 +751,7 @@ jobs:
cargo test --workspace --all-targets

- name: Warm WSL world (Windows self-hosted; WAPS)
if: startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-agent-policy-snapshot')
if: startsWith(inputs.feature_dir, 'docs/project_management/_archived/world-service-policy-snapshot')
shell: pwsh
env:
# The Windows WSL backend is expected to use the named pipe forwarder; disable the TCP bridge
Expand Down Expand Up @@ -828,7 +828,7 @@ jobs:
if [[ ! -S "${sock}" ]]; then
echo "SUBSTRATE_RUNNER_MISPROVISIONED=1"
echo "SUBSTRATE_RUNNER_MISPROVISIONED_REASON=substrate_sock_missing"
echo "WSL runner is missing required world-agent socket: ${sock}" >&2
echo "WSL runner is missing required world-service socket: ${sock}" >&2
echo "Remediation: provision the world agent + ensure the runner user can access ${sock} (root:substrate 0660)." >&2
echo "Diagnostics: id=$(id -a || true)" >&2
exit 1
Expand All @@ -837,7 +837,7 @@ jobs:
if [[ ! -w "${sock}" ]]; then
echo "SUBSTRATE_RUNNER_MISPROVISIONED=1"
echo "SUBSTRATE_RUNNER_MISPROVISIONED_REASON=substrate_sock_permission_denied"
echo "WSL runner cannot access required world-agent socket: ${sock} (need write permission to connect)" >&2
echo "WSL runner cannot access required world-service socket: ${sock} (need write permission to connect)" >&2
echo "Remediation: ensure runner user is in substrate group + restart runner service; confirm ${sock} is root:substrate 0660." >&2
ls -l "${sock}" >&2 || true
stat "${sock}" >&2 || true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ jobs:
- name: Targeted replay tests
run: cargo test -p substrate-replay -- --nocapture

- name: Targeted world-agent tests
run: cargo test -p world-agent -- --nocapture
- name: Targeted world-service tests
run: cargo test -p world-service -- --nocapture

- name: Install dist CLI
run: |
Expand Down
14 changes: 7 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ Substrate is the secure execution layer that sits between AI agents and a develo
- `crates/shell`: interactive REPL, PTY plumbing, shim deployment, and world orchestration.
- `crates/shim`: PATH interception, depth tracking (`SHIM_DEPTH`), and structured logging of every spawned process.
- `crates/common`: shared log schema, redaction helpers, filesystem diff types.
- `crates/world*`: platform-specific backends. `world` uses namespaces/cgroups/nftables on Linux; `world-mac-lima` boots a Lima VM and tunnels to `world-agent`; `world-windows-wsl` warms a WSL distro and brokers named-pipe/TCP access (functional but experimental).
- `crates/world-agent`: the in-world daemon exposing REST (`/v1/execute`) and WebSocket (`/v1/stream`) APIs with fs diff collection.
- `crates/world*`: platform-specific backends. `world` uses namespaces/cgroups/nftables on Linux; `world-mac-lima` boots a Lima VM and tunnels to `world-service`; `world-windows-wsl` warms a WSL distro and brokers named-pipe/TCP access (functional but experimental).
- `crates/world-service`: the in-world daemon exposing REST (`/v1/execute`) and WebSocket (`/v1/stream`) APIs with fs diff collection.
- `crates/agent-api-*`: shared request/response models, async client, and host proxy helpers for third-party agents.
- `crates/broker`, `forwarder`, `host-proxy`, `telemetry-lib`, `replay`, `substrate-graph`: policy decisions, transport glue, telemetry pipelines, replay tooling, and optional graph analytics.
- `docs/`: deep dives (`WORLD.md`, `TRACE.md`, `REPLAY.md`, `TELEMETRY.md`, `CONFIGURATION.md`, `cross-platform/…`).
Expand All @@ -19,8 +19,8 @@ Substrate is the secure execution layer that sits between AI agents and a develo
## Execution Architecture
1. Shell loads policy via the broker (`substrate_broker::evaluate`), ensures shims are deployed (`ShimDeployer`), and initializes tracing (`substrate_trace::init_trace`).
2. The shim intercepts PATH lookups, writes structured execution events (via `logger::log_execution`), performs fast policy checks, and forwards invocation metadata to trace spans.
3. The shell consults the world backend selected by `world-backend-factory`, issuing `/v1/execute` for non-PTY runs or upgrading to `/v1/stream` for interactive workloads. On Linux/macOS this depends on the `substrate-world-agent` service (systemd on Linux, Lima guest on macOS); provisioning scripts install and start that service.
4. `world-agent` executes inside a per-session world: Linux uses cgroup v2 + netns + overlayfs; macOS proxies into a Lima VM via VSock/SSH; Windows calls into WSL using named pipes or a TCP forwarder.
3. The shell consults the world backend selected by `world-backend-factory`, issuing `/v1/execute` for non-PTY runs or upgrading to `/v1/stream` for interactive workloads. On Linux/macOS this depends on the `substrate-world-service` service (systemd on Linux, Lima guest on macOS); provisioning scripts install and start that service.
4. `world-service` executes inside a per-session world: Linux uses cgroup v2 + netns + overlayfs; macOS proxies into a Lima VM via VSock/SSH; Windows calls into WSL using named pipes or a TCP forwarder.
5. Results, filesystem diffs, and policy decisions are recorded by `crates/trace`, producing JSONL spans in `~/.substrate/trace.jsonl` (or `SHIM_TRACE_LOG`). Replay (`crates/replay`) re-runs spans through the same world backend (Linux replays require CAP_SYS_ADMIN for namespaces/overlay; use `--no-world` / `SUBSTRATE_REPLAY_USE_WORLD=disabled` only if you want to opt out).

## Local Environment & Core Tools
Expand Down Expand Up @@ -55,14 +55,14 @@ cargo bench # exercise hotspots when touching pe
- Replay and diff analysis live in `docs/REPLAY.md` and `docs/TRACE.md`; update those docs when schema changes. See `docs/REPLAY.md` for privileged requirements (`SUBSTRATE_REPLAY_USE_WORLD`) and how to use `--no-world` when isolation isn’t available.

## Platform Worlds & Provisioning
- **Linux**: Run `scripts/linux/world-provision.sh --profile release` to install `world-agent` plus the matching `.service`/`.socket` units so systemd manages `/run/substrate.sock`. Dev installs invoke this script automatically (sudo prompts expected). The installers now create the `substrate` group, add the invoking user, and reload the socket units so `/run/substrate.sock` is `root:substrate 0660` just like the provisioning script. After provisioning, run `id -nG "$USER"` to confirm the new membership and `loginctl enable-linger "$USER"` so the socket-activated service is available after logout/reboot. Validate with `systemctl status substrate-world-agent.socket`, `systemctl status substrate-world-agent.service`, and `substrate world doctor --json | jq '.world_socket'`.
- **Linux**: Run `scripts/linux/world-provision.sh --profile release` to install `world-service` plus the matching `.service`/`.socket` units so systemd manages `/run/substrate.sock`. Dev installs invoke this script automatically (sudo prompts expected). The installers now create the `substrate` group, add the invoking user, and reload the socket units so `/run/substrate.sock` is `root:substrate 0660` just like the provisioning script. After provisioning, run `id -nG "$USER"` to confirm the new membership and `loginctl enable-linger "$USER"` so the socket-activated service is available after logout/reboot. Validate with `systemctl status substrate-world-service.socket`, `systemctl status substrate-world-service.service`, and `substrate world doctor --json | jq '.world_socket'`.
- **macOS**: `scripts/mac/lima-warm.sh` provisions the `substrate` Lima VM, installs dependencies, and ensures forwarding. `scripts/mac/lima-doctor.sh` and `scripts/mac/smoke.sh` validate PTY, REST, and replay flows.
- **Windows**: Warm the WSL backend via `pwsh -File scripts/windows/wsl-warm.ps1 -DistroName substrate-wsl -ProjectPath (Resolve-Path .)`; verify with `scripts/windows/wsl-smoke.ps1`. The backend prefers named-pipe transport but can fall back to TCP (`SUBSTRATE_FORWARDER_PORT`).
- Always capture doctor/smoke output in PRs touching `world-*`, `forwarder`, or `host-proxy` crates.

## Testing & Validation Expectations
- Unit tests live alongside sources (`#[cfg(test)] mod tests`); integration suites sit in `crates/*/tests/` (e.g., `crates/shell/tests/integration.rs`, `crates/replay/tests/`). Use `test_<behavior>` naming.
- Run `cargo test -p world-agent`, `cargo test -p substrate-shim`, and targeted `cargo test --test shim_deployment` when editing those components.
- Run `cargo test -p world-service`, `cargo test -p substrate-shim`, and targeted `cargo test --test shim_deployment` when editing those components.
- When touching shell/world/shim logic, capture `substrate world doctor --json`, `substrate shim doctor --json`, and `substrate health --json` output in the PR.
- Privileged checks (netns, nftables, cgroups) require `docs/HOWTO_PRIVILEGED_TESTS.md`; document platform coverage in PR descriptions.
- Validate shim lifecycle on every OS touched: `substrate --shim-status`, `substrate --shim-deploy`, `substrate --shim-remove`.
Expand Down 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** (49012 symbols, 75513 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** (49108 symbols, 75625 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
Loading