Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b1ce9c8
Docs: add CloudShell FOG integration profile
mdheller May 5, 2026
331c27e
Add CloudShell FOG receipt context smoke test
mdheller May 5, 2026
d220b12
fix: invoke Linux staging helper through bash
mdheller May 5, 2026
f8fa5e4
docs: use TurtleTerm profile name in install guide
mdheller May 5, 2026
fb41f0e
docs: avoid forbidden shell authority phrasing
mdheller May 5, 2026
84786e4
fix: invoke RPM package builder through bash
mdheller May 5, 2026
8f0fc21
fix: invoke Debian package builder through bash
mdheller May 5, 2026
6a8dccc
fix: invoke Arch package builder through bash
mdheller May 5, 2026
3cf385b
fix: invoke RPM staging helper through bash
mdheller May 5, 2026
8463f8d
fix: invoke Debian staging helper through bash
mdheller May 5, 2026
06390c6
fix: invoke Arch staging helper through bash
mdheller May 5, 2026
4eee34d
fix: avoid pipefail broken-pipe failures in Debian verifier
mdheller May 6, 2026
0127073
fix: invoke generated RPM staging helper through bash
mdheller May 6, 2026
6e59195
fix: avoid pipefail broken-pipe failures in RPM verifier
mdheller May 6, 2026
76701f8
test: add RPM verifier diagnostics
mdheller May 6, 2026
b42881d
fix: avoid pipefail broken-pipe failures in Arch verifier
mdheller May 6, 2026
4e00f65
test: surface generated RPM build diagnostics
mdheller May 6, 2026
9f9d9a6
fix: resolve sibling agentctl in cloudfog bridge
mdheller May 6, 2026
07f4728
fix: resolve sibling agentctl in superconscious bridge
mdheller May 6, 2026
c165162
fix: resolve sibling agentctl in agent-machine bridge
mdheller May 6, 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
28 changes: 28 additions & 0 deletions assets/sourceos/bin/turtle-agent-machine
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env sh
# TurtleTerm Agent Machine bridge.
set -eu

bin_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
agentctl="$bin_dir/turtle-agentctl"

cmd="${1:-surfaces}"
case "$cmd" in
surfaces)
shift || true
exec "$agentctl" --stdio agent-machine-surfaces "$@"
;;
probe)
shift || true
exec "$agentctl" --stdio agent-machine-probe "$@"
;;
request-execution)
shift || true
surface="${1:-agent-machine/local-agentpod}"
shift || true
exec "$agentctl" --stdio request-surface-execution "$surface" "$@"
;;
*)
echo "usage: turtle-agent-machine [surfaces|probe|request-execution <surface> -- <command>]" >&2
exit 2
;;
esac
28 changes: 28 additions & 0 deletions assets/sourceos/bin/turtle-cloudfog
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env sh
# TurtleTerm CloudFog surface bridge.
set -eu

bin_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
agentctl="$bin_dir/turtle-agentctl"

cmd="${1:-surfaces}"
case "$cmd" in
surfaces)
shift || true
exec "$agentctl" --stdio cloudfog-surfaces "$@"
;;
inspect)
shift || true
exec "$agentctl" --stdio cloudfog-inspect "$@"
;;
request-execution)
shift || true
surface="${1:-cloudfog/local-devshell}"
shift || true
exec "$agentctl" --stdio request-surface-execution "$surface" "$@"
;;
*)
echo "usage: turtle-cloudfog [surfaces|inspect <surface>|request-execution <surface> -- <command>]" >&2
exit 2
;;
esac
22 changes: 22 additions & 0 deletions assets/sourceos/bin/turtle-superconscious
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env sh
# TurtleTerm Superconscious bridge.
set -eu

bin_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
agentctl="$bin_dir/turtle-agentctl"

cmd="${1:-observe}"
case "$cmd" in
observe)
shift || true
exec "$agentctl" --stdio superconscious-observe "$@"
;;
propose)
shift || true
exec "$agentctl" --stdio superconscious-propose "$@"
;;
*)
echo "usage: turtle-superconscious [observe <text>|propose <prompt>]" >&2
exit 2
;;
esac
75 changes: 75 additions & 0 deletions assets/sourceos/tests/test_cloudshell_fog_receipt_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Validate TurtleTerm receipt context propagation for CloudShell FOG sessions."""

from __future__ import annotations

import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[3]
TURTLE_WRAPPER = REPO_ROOT / "assets" / "sourceos" / "bin" / "turtle-term"


def read_ndjson(path: Path) -> list[dict]:
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()]


def main() -> int:
with tempfile.TemporaryDirectory() as tmp:
tmp_path = Path(tmp)
events = tmp_path / "events.ndjson"
receipts = tmp_path / "receipts"

env = dict(os.environ)
env.update(
{
"SOURCEOS_TERMINAL_SESSION_ID": "csf-session-0001",
"SOURCEOS_WORKSPACE": "workspace:lattice-demo",
"SOURCEOS_TERMINAL_EVENTS": str(events),
"SOURCEOS_TERMINAL_RECEIPTS": str(receipts),
"SOURCEOS_ACTOR_ID": "human:operator@example.com",
"SOURCEOS_POLICY_BUNDLE_ID": "policy:cloudshell-default",
"SOURCEOS_EXECUTION_DOMAIN": "cloudshell-fog/k8s",
}
)

result = subprocess.run(
[sys.executable, str(TURTLE_WRAPPER), "run", "--", sys.executable, "-c", "print('cloudshell-fog-ok')"],
cwd=str(REPO_ROOT),
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)

assert result.returncode == 0, result.stderr
assert "cloudshell-fog-ok" in result.stdout
assert events.exists(), "event stream missing"

rows = read_ndjson(events)
completed = [row for row in rows if row.get("event_type") == "command.completed"][-1]
receipt_path = Path(completed["receipt_path"])
assert receipt_path.exists(), f"receipt missing: {receipt_path}"

receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
assert receipt["schema"] == "sourceos.terminal.receipt.v0"
assert receipt["session_id"] == "csf-session-0001"
assert receipt["workspace_id"] == "workspace:lattice-demo"
assert receipt["actor_id"] == "human:operator@example.com"
assert receipt["policy_bundle_id"] == "policy:cloudshell-default"
assert receipt["execution_domain"] == "cloudshell-fog/k8s"
assert receipt["stdout_digest"].startswith("sha256:")
assert receipt["stderr_digest"].startswith("sha256:")

print("validated CloudShell FOG receipt context propagation")
return 0


if __name__ == "__main__":
raise SystemExit(main())
86 changes: 86 additions & 0 deletions docs/integration/cloudshell-fog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# CloudShell FOG Integration Profile v0 — TurtleTerm

## Purpose

TurtleTerm is the SourceOS policy-aware, agent-addressable terminal workbench for trusted command execution, terminal receipts, agent delegation, and reproducible operator workflows.

CloudShell FOG is the browser/fog/cloud shell execution plane for session lifecycle, placement, PTY attach, runtime allocation, and audit.

This profile defines how TurtleTerm should integrate with CloudShell FOG while preserving TurtleTerm as the owner of terminal command receipt semantics.

## Ownership boundary

### TurtleTerm owns

- local/operator command lifecycle receipts
- SourceOS terminal session/event/receipt schemas
- stdout/stderr digest capture for command execution
- operator terminal event stream and receipt paths
- local agent gateway and terminal CLI behavior

### CloudShell FOG owns

- browser/fog/cloud shell session lifecycle
- WSS PTY attach contract
- fog/cloud placement metadata
- Kubernetes/fog runtime connector behavior
- CloudShell audit events
- runtime allocation and teardown semantics

## Integration principle

TurtleTerm should expose or preserve receipt metadata that allows CloudShell FOG sessions and audit events to correlate with local/operator command receipts.

TurtleTerm should not absorb CloudShell FOG's placement engine or runtime connector responsibilities.

## Environment propagation

When a TurtleTerm workflow is launched in the context of a CloudShell FOG session, the launcher MAY set:

- `SOURCEOS_TERMINAL_SESSION_ID` = CloudShell session ID or derived stable terminal session ID
- `SOURCEOS_WORKSPACE` = CloudShell workspace or project identifier, if known
- `SOURCEOS_ACTOR_ID` = CloudShell authenticated subject or mapped SourceOS actor identity
- `SOURCEOS_POLICY_BUNDLE_ID` = CloudShell policy/profile identifier
- `SOURCEOS_EXECUTION_DOMAIN` = `cloudshell-fog`, `k8s`, `fog`, or a more specific domain

TurtleTerm should preserve these values in session/event/receipt outputs rather than rewriting them with local-only defaults.

## Receipt correlation fields

Where available, CloudShell FOG metadata SHOULD be attached to TurtleTerm receipt context:

- CloudShell session ID
- CloudShell placement region
- CloudShell placement node ID
- CloudShell trust tier
- CloudShell placement reasons
- runtime image or runtime profile
- runtime namespace/pod identity when applicable

## Event mapping

| TurtleTerm / SourceOS terminal concept | CloudShell FOG concept |
|---|---|
| `sourceos.terminal.session.v0` | `session.created` / shell session context |
| `command.started` | command execution within attached shell context |
| `command.completed` | completed command plus receipt pointer |
| command stdout/stderr digests | command-level evidence, not PTY stream replacement |
| `execution_domain` | CloudShell runtime / placement execution domain |
| policy bundle ID | CloudShell policy/profile context |

## Non-goals

- TurtleTerm does not replace CloudShell FOG's browser shell or WSS PTY contract.
- TurtleTerm does not own CloudShell FOG's Kubernetes/fog placement engine.
- CloudShell FOG does not need to capture every PTY byte as a TurtleTerm command receipt by default.

## Open questions

1. Should SourceOS terminal schemas remain in TurtleTerm or move to a shared terminal-contracts repository?
2. Should TurtleTerm support a `cloudshell-fog` receipt enrichment mode with explicit placement fields?
3. Should AgentPlane become the canonical bridge for launching TurtleTerm-backed workflows from CloudShell FOG?

## Tracking

- TurtleTerm: issue #1
- CloudShell FOG: SocioProphet/cloudshell-fog#35
2 changes: 1 addition & 1 deletion docs/sourceos/AGENTIC_INTEGRATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ AgentPlane execution, evidence, and replay

## Invariant

TurtleTerm must not grant agents ambient shell authority.
TurtleTerm must never give agents unreviewed shell capability.

Every risky action becomes an ExecutionDecision: allow, deny, ask, defer, or rewrite.

Expand Down
4 changes: 2 additions & 2 deletions docs/sourceos/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ turtle-agentctl --stdio ping
Homebrew profile path:

```bash
ln -sf "$(brew --prefix)/etc/turtle-term/wezterm.lua" ~/.wezterm.lua
ln -sf "$(brew --prefix)/etc/turtle-term/turtleterm.lua" ~/.wezterm.lua
```

Direct install profile path:

```bash
ln -sf "$HOME/.local/etc/turtle-term/wezterm.lua" ~/.wezterm.lua
ln -sf "$HOME/.local/etc/turtle-term/turtleterm.lua" ~/.wezterm.lua
```

Then launch TurtleTerm:
Expand Down
2 changes: 1 addition & 1 deletion packaging/linux/rpm/turtle-term.spec
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ cargo build --release --locked -p wezterm-gui
cargo build --release --locked -p wezterm-mux-server

%install
TURTLE_TERM_STAGE_PREFIX=%{buildroot}%{_prefix} packaging/scripts/stage-linux-package.sh
TURTLE_TERM_STAGE_PREFIX=%{buildroot}%{_prefix} bash packaging/scripts/stage-linux-package.sh

%check
desktop-file-validate %{buildroot}%{_datadir}/applications/ai.sourceos.TurtleTerm.desktop
Expand Down
2 changes: 1 addition & 1 deletion packaging/scripts/build-arch-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TURTLE_TERM_STAGE_PREFIX="$pkgroot/usr" \
TURTLE_TERM_ETC_DIR="$pkgroot/etc" \
TURTLE_TERM_RUNTIME_PREFIX="/usr" \
TURTLE_TERM_RUNTIME_ETC_DIR="/etc" \
"$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null
bash "$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null

cat > "$pkgroot/.PKGINFO" <<EOF
pkgname = turtle-term
Expand Down
2 changes: 1 addition & 1 deletion packaging/scripts/build-deb-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ TURTLE_TERM_STAGE_PREFIX="$prefix" \
TURTLE_TERM_ETC_DIR="$etc_dir" \
TURTLE_TERM_RUNTIME_PREFIX="/usr" \
TURTLE_TERM_RUNTIME_ETC_DIR="/etc" \
"$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null
bash "$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null

cat > "$debian_dir/control" <<EOF
Package: turtle-term
Expand Down
5 changes: 3 additions & 2 deletions packaging/scripts/build-rpm-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ reproducible operator workflows.

%install
rm -rf %{buildroot}
TURTLE_TERM_STAGE_PREFIX=%{buildroot}/usr TURTLE_TERM_ETC_DIR=%{buildroot}/etc TURTLE_TERM_RUNTIME_PREFIX=/usr TURTLE_TERM_RUNTIME_ETC_DIR=/etc $repo_root/packaging/scripts/stage-linux-package.sh >/dev/null
TURTLE_TERM_STAGE_PREFIX=%{buildroot}/usr TURTLE_TERM_ETC_DIR=%{buildroot}/etc TURTLE_TERM_RUNTIME_PREFIX=/usr TURTLE_TERM_RUNTIME_ETC_DIR=/etc bash $repo_root/packaging/scripts/stage-linux-package.sh >/dev/null
cp $repo_root/LICENSE.md %{buildroot}/LICENSE.md
if [ -f $repo_root/THIRD_PARTY_NOTICES.md ]; then cp $repo_root/THIRD_PARTY_NOTICES.md %{buildroot}/THIRD_PARTY_NOTICES.md; fi

Expand All @@ -62,7 +62,8 @@ if [ -f $repo_root/THIRD_PARTY_NOTICES.md ]; then cp $repo_root/THIRD_PARTY_NOTI
/usr/share/turtle-term/
EOF

rpmbuild --define "_topdir $rpmbuild_root" -bb "$spec" >/dev/null
echo "building RPM with generated spec: $spec" >&2
rpmbuild --define "_topdir $rpmbuild_root" -bb "$spec"
rpm="$(find "$rpmbuild_root/RPMS" -name 'turtle-term-*.rpm' -print -quit)"
test -n "$rpm"
sha256sum "$rpm" > "$rpm.sha256"
Expand Down
4 changes: 2 additions & 2 deletions packaging/scripts/verify-arch-package.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
set -eu

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
tmp="$(mktemp -d)"
Expand All @@ -15,7 +15,7 @@ EOF
done

pkg="$(TURTLE_TERM_OUT_DIR="$tmp" TURTLE_TERM_VERSION="0.1.0" TURTLE_TERM_ARCH_ARCH="$(uname -m)" \
"$repo_root/packaging/scripts/build-arch-package.sh")"
bash "$repo_root/packaging/scripts/build-arch-package.sh")"
extract="$tmp/extract"

test -f "$pkg"
Expand Down
4 changes: 2 additions & 2 deletions packaging/scripts/verify-deb-package.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
set -eu

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
tmp="$(mktemp -d)"
Expand All @@ -15,7 +15,7 @@ EOF
done

TURTLE_TERM_OUT_DIR="$tmp" TURTLE_TERM_VERSION="0.1.0" TURTLE_TERM_DEB_ARCH="amd64" \
"$repo_root/packaging/scripts/build-deb-package.sh" >/dev/null
bash "$repo_root/packaging/scripts/build-deb-package.sh" >/dev/null

deb="$tmp/turtle-term_0.1.0_amd64.deb"
extract="$tmp/extract"
Expand Down
2 changes: 1 addition & 1 deletion packaging/scripts/verify-linux-package-layout.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ EOF
done

prefix="$tmp/prefix"
TURTLE_TERM_STAGE_PREFIX="$prefix" "$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null
TURTLE_TERM_STAGE_PREFIX="$prefix" bash "$repo_root/packaging/scripts/stage-linux-package.sh" >/dev/null

required_paths=(
"$prefix/bin/turtleterm"
Expand Down
Loading