Back to feed

sledtools/pika branch #100

pika-cloud-local-result-fragment

Share local guest result fragment

Target branch: master

Merge Commit: 28ab59d4b3294de39b81600b5cb0788cdcb99807

branch: merged tutorial: ready ci: success
Open CI Details

Continuous Integration

CI: success

Compact status on the review page, with full logs on the CI page.

Open CI Details

Latest run #126 success

10 passed

head edeab30cf2cd5cff2d9466f6c3cbd59eb1c6df38 · queued 2026-03-26 01:51:11 · 10 lane(s)

queued 6s · ran 1m 58s

check-pika-rust · success check-pika-followup · success check-notifications · success check-agent-contracts · success check-rmp · success check-pikachat · success check-pikachat-typescript · success check-apple-host-sanity · success check-pikachat-openclaw-e2e · success check-fixture · success

Summary

This branch extracts the duplicated shell logic that writes a terminal result JSON file into a single shared template (local-terminal-result-fragment.sh.in). Previously, both the Rust executor (macOS/Tart path) and the Nix guest module (Linux/Incus path) contained identical inline shell blocks for determining pass/fail status and serializing result.json. The new template uses placeholder tokens (__PIKACI_RESULT_PATH__, __PIKACI_SCHEMA_VERSION__, __PIKACI_FINISHED_AT_COMMAND__) that each consumer replaces at build/render time with environment-appropriate values. This eliminates the duplication, makes the result contract easier to audit in one place, and adds targeted tests that pin both the template content and each consumer's integration with it.

Tutorial Steps

Introduce the shared shell template

Intent: Create a single source-of-truth shell fragment that writes the terminal result JSON, parameterized with placeholder tokens so it can be reused by different execution backends.

Affected files: nix/pikaci/local-terminal-result-fragment.sh.in

Evidence
@@ -0,0 +1,16 @@
+status="completed"
+message="test passed"
+if [ "$code" -ne 0 ]; then
+  status="failed"
+  message="test command exited with $code"
+fi
+
+cat > __PIKACI_RESULT_PATH__ <<EOF
+{
+  "schema_version": __PIKACI_SCHEMA_VERSION__,
+  "status": "$status",
+  "exit_code": $code,
+  "finished_at": "$(__PIKACI_FINISHED_AT_COMMAND__)",
+  "message": "$message"
+}
+EOF

A new file nix/pikaci/local-terminal-result-fragment.sh.in is added. It contains the shell logic that was previously duplicated in both the Rust executor and the Nix guest module:

  1. Set status and message based on exit code ($code).
  2. Write a JSON object to a file via a heredoc.

Three placeholder tokens make the template generic:

TokenPurpose
__PIKACI_RESULT_PATH__Destination file path for the JSON result
__PIKACI_SCHEMA_VERSION__Integer schema version of the lifecycle contract
__PIKACI_FINISHED_AT_COMMAND__Shell command that produces an ISO-8601 timestamp

Each consumer replaces these tokens with values appropriate to its platform (e.g., date -Iseconds on Linux vs date -u +"%Y-%m-%dT%H:%M:%SZ" on macOS).

Adopt the template in the Rust executor (macOS / Tart)

Intent: Replace the inline result-writing shell block in the Rust-side local script builder with a call to a new `render_local_terminal_result_fragment` function that performs token substitution on the shared template.

Affected files: crates/pikaci/src/executor.rs

Evidence
@@ -203,6 +203,8 @@ const TART_XCODE_TAG: &str = "pikaci-xcode";
 const TART_LIBRARY_DEVELOPER_TAG: &str = "pikaci-library-developer";
 const TART_RUST_TOOLCHAIN_NAME: &str = "rust-toolchain";
 const TART_NIX_STORE_TAG: &str = "pikaci-nix-store";
+const LOCAL_TERMINAL_RESULT_FRAGMENT_TEMPLATE: &str =
+    include_str!("../../../nix/pikaci/local-terminal-result-fragment.sh.in");
@@ -1624,6 +1626,10 @@ fi
+    let terminal_result_fragment = render_local_terminal_result_fragment(
+        &format!("\"{artifacts_mount}/result.json\""),
+        r#"date -u +"%Y-%m-%dT%H:%M:%SZ""#,
+    );
@@ -1640,25 +1646,21 @@ set +e
 {user_command}
 code=$?
 set -e
-status="completed"
-message="test passed"
-if [ "$code" -ne 0 ]; then
-  status="failed"
-  message="test command exited with $code"
-fi
-cat > "{artifacts_mount}/result.json" <<EOF
 ...
+{terminal_result_fragment}

The Rust executor embeds the template at compile time with include_str! into the constant LOCAL_TERMINAL_RESULT_FRAGMENT_TEMPLATE.

A new helper function render_local_terminal_result_fragment performs three str::replace calls:

fn render_local_terminal_result_fragment(result_path: &str, finished_at_command: &str) -> String {
    LOCAL_TERMINAL_RESULT_FRAGMENT_TEMPLATE
        .replace("__PIKACI_RESULT_PATH__", result_path)
        .replace("__PIKACI_SCHEMA_VERSION__", &LIFECYCLE_SCHEMA_VERSION.to_string())
        .replace("__PIKACI_FINISHED_AT_COMMAND__", finished_at_command)
}

The ~15-line inline shell block in the local script builder is deleted and replaced with a single {terminal_result_fragment} interpolation. The macOS-specific arguments are:

  • result_path: "{artifacts_mount}/result.json" (quoted for shell safety)
  • finished_at_command: date -u +"%Y-%m-%dT%H:%M:%SZ" (macOS-compatible UTC format)

Adopt the template in the Nix guest module (Linux / Incus)

Intent: Replace the inline result-writing shell block in the NixOS guest module with a Nix-native rendering function that reads and substitutes the same shared template.

Affected files: nix/pikaci/guest-module.nix

Evidence
@@ -43,6 +43,21 @@ let
+  localTerminalResultFragment = builtins.readFile ./local-terminal-result-fragment.sh.in;
+  renderLocalTerminalResultFragment =
+    resultPath: finishedAtCommand:
+    builtins.replaceStrings
+      [
+        "__PIKACI_RESULT_PATH__"
+        "__PIKACI_SCHEMA_VERSION__"
+        "__PIKACI_FINISHED_AT_COMMAND__"
+      ]
+      [
+        resultPath
+        "1"
+        finishedAtCommand
+      ]
+      localTerminalResultFragment;
@@ -205,22 +220,7 @@ in
-      status="completed"
-      message="test passed"
 ...
+      ${renderLocalTerminalResultFragment "/artifacts/result.json" "date -Iseconds"}

On the Nix side, the template is loaded with builtins.readFile and a two-argument function renderLocalTerminalResultFragment is defined using builtins.replaceStrings.

The Linux-specific arguments are:

  • resultPath: /artifacts/result.json (the fixed mount point inside the Incus guest)
  • finishedAtCommand: date -Iseconds (GNU coreutils ISO-8601 shorthand)

The previous ~16-line inline block in the systemd service script is replaced by a single Nix string interpolation:

${renderLocalTerminalResultFragment "/artifacts/result.json" "date -Iseconds"}

Note that the schema version is hard-coded to "1" on the Nix side. This mirrors the Rust side where LIFECYCLE_SCHEMA_VERSION is also 1, but it is a string literal here rather than a programmatic reference—a point to watch if the schema version ever increments.

Update and expand the test suite

Intent: Ensure the shared template's content is pinned by contract tests, and verify that both consumers (Rust executor and Nix guest module) correctly integrate with it.

Affected files: crates/pikaci/src/executor.rs

Evidence
@@ -2484,6 +2486,10 @@ mod tests {
+    fn local_terminal_result_fragment_source() -> &'static str {
+        include_str!("../../../nix/pikaci/local-terminal-result-fragment.sh.in")
+    }
@@ -2658,19 +2664,19 @@ mod tests {
-    fn local_linux_guest_module_pins_shared_terminal_result_contract() {
-        let source = local_linux_guest_module_source();
+    fn local_terminal_result_fragment_pins_shared_terminal_result_contract() {
+        let source = local_terminal_result_fragment_source();
         assert_contains_all(
             source,
             &[
                 "status=\"completed\"",
                 "status=\"failed\"",
-                "cat > /artifacts/result.json <<EOF",
-                "\"schema_version\": 1",
+                "cat > __PIKACI_RESULT_PATH__ <<EOF",
+                "\"schema_version\": __PIKACI_SCHEMA_VERSION__",
@@ -2678,6 +2684,25 @@ mod tests {
+    fn local_linux_guest_module_uses_shared_terminal_result_fragment() {
+        let source = local_linux_guest_module_source();
+        assert_contains_all(
+            source,
+            &[
+                "localTerminalResultFragment = builtins.readFile ./local-terminal-result-fragment.sh.in;",
+                "renderLocalTerminalResultFragment =",
+                "\"__PIKACI_RESULT_PATH__\"",
+                "\"__PIKACI_SCHEMA_VERSION__\"",
+                "\"__PIKACI_FINISHED_AT_COMMAND__\"",
+                "\"/artifacts/result.json\"",
+                "\"date -Iseconds\"",
+                "${renderLocalTerminalResultFragment \"/artifacts/result.json\" \"date -Iseconds\"}",
+            ],
+        );

Three test changes maintain the contract-pinning strategy:

  1. local_terminal_result_fragment_pins_shared_terminal_result_contract (renamed from local_linux_guest_module_pins_shared_terminal_result_contract): Now asserts against the template file directly instead of the guest module. The expected strings use placeholder tokens (__PIKACI_RESULT_PATH__, etc.) rather than hard-coded Linux values. This pins the template's structure.

  2. local_linux_guest_module_uses_shared_terminal_result_fragment (new): Asserts that the Nix guest module source contains the readFile import, the renderLocalTerminalResultFragment function definition, all three placeholder token strings, the Linux-specific arguments (/artifacts/result.json, date -Iseconds), and the actual interpolation call. This ensures the Nix consumer stays wired to the shared template.

  3. A helper local_terminal_result_fragment_source() is added to load the template in test context via include_str!, matching the existing pattern used for local_linux_guest_module_source().

Diff