Back to feed

sledtools/pika branch #137

pika-managed-agent-contract-extract

Extract shared managed agent contract

Target branch: master

Merge Commit: 24a5a6c90c75364dc5b351e3af21f8b207cd2111

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

Continuous Integration

CI: failed

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

Open CI Details

Latest run #173 failed

8 passed 1 failed

head 01e8edc203904aa5ce10696dfdc77addcba96af0 · queued 2026-03-27 01:09:22 · 9 lane(s)

queued 15s · ran 40s

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

Summary

This branch extracts the shared managed-agent contract types (AgentStartupPhase, IncusProvisionParams, ManagedVmProvisionParams, AgentProvisionRequest) out of the pika-cloud crate into a new, lightweight pika-managed-agent-contract crate. The motivation is to decouple consumers that only need the agent provisioning contract (the CLI, the Rust SDK, and pika-server) from the heavier pika-cloud crate and its transitive dependencies. The new crate depends only on serde and serde_json, the relocated types and their tests are identical to the originals, and every import site is updated to point at the new crate.

Tutorial Steps

Create the new `pika-managed-agent-contract` crate

Intent: Introduce a minimal crate whose sole purpose is to house the shared agent-provisioning types so they can be depended on without pulling in `pika-cloud`.

Affected files: crates/pika-managed-agent-contract/Cargo.toml, crates/pika-managed-agent-contract/src/lib.rs

Evidence
@@ -0,0 +1,8 @@
+[package]
+name = "pika-managed-agent-contract"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+serde = { workspace = true }
+serde_json = { workspace = true }
@@ -0,0 +1,99 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub enum AgentStartupPhase {

A new crate pika-managed-agent-contract is created under crates/ with only serde and serde_json as dependencies. It contains the four types that previously lived in pika-cloud:

  • AgentStartupPhase — enum tracking the lifecycle of an agent boot.
  • IncusProvisionParams — optional Incus-specific provisioning knobs.
  • ManagedVmProvisionParams — thin wrapper with #[serde(deny_unknown_fields)].
  • AgentProvisionRequest — the top-level request struct with a convenience managed_vm_params() method.

All derive macros, serde attributes, and the impl block are carried over verbatim. Three unit tests (round_trips_incus_backend, managed_vm_params_preserve_incus_request_shape, rejects_removed_legacy_fields) are included directly in the new crate, keeping the contract self-testing.

Register the crate in the workspace

Intent: Make the new crate visible to Cargo's workspace resolver and define a workspace-level dependency so downstream crates can reference it via `{ workspace = true }`.

Affected files: Cargo.toml, Cargo.lock

Evidence
@@ -8,6 +8,7 @@ members = [
   "crates/pika-forge-model",
   "crates/pikaci",
   "crates/pika-agent-protocol",
+  "crates/pika-managed-agent-contract",
@@ -35,6 +36,7 @@ mdk-storage-traits = { git = ...
+pika-managed-agent-contract = { path = "crates/pika-managed-agent-contract" }
@@ -6026,6 +6026,14 @@ dependencies = [
+[[package]]
+name = "pika-managed-agent-contract"
+version = "0.1.0"
+dependencies = [
+ "serde",
+ "serde_json",
+]

Cargo.toml at the workspace root is updated in two places:

  1. The members array gains crates/pika-managed-agent-contract.
  2. A new [workspace.dependencies] entry maps the crate name to its local path.

Cargo.lock is regenerated and now contains the new package with its two dependencies.

Remove the types and tests from `pika-cloud`

Intent: Delete the now-duplicated type definitions and their tests from the original location to establish a single source of truth.

Affected files: crates/pika-cloud/src/lib.rs

Evidence
@@ -36,60 +36,6 @@ pub enum ProviderKind {
-#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
-#[serde(rename_all = "snake_case")]
-pub enum AgentStartupPhase {
@@ -121,34 +67,6 @@ mod tests {
-    #[test]
-    fn agent_provision_request_round_trips_incus_backend() {

The four structs/enums (AgentStartupPhase, IncusProvisionParams, ManagedVmProvisionParams, AgentProvisionRequest), the impl AgentProvisionRequest block, and the two related tests (agent_provision_request_round_trips_incus_backend, agent_provision_request_rejects_removed_legacy_fields) are all removed from crates/pika-cloud/src/lib.rs. The remaining pika-cloud types (ProviderKind, IncusGuestRunRequest, etc.) stay in place.

Re-point `pika-server` to the new crate

Intent: The server crate needs both `pika-cloud` (for other cloud types) and the new contract crate. Add the new dependency and update the re-export.

Affected files: crates/pika-server/Cargo.toml, crates/pika-server/src/managed_runtime_contract.rs

Evidence
@@ -19,6 +19,7 @@ futures = { workspace = true }
+pika-managed-agent-contract = { workspace = true }
@@ -1,6 +1,6 @@
-pub(crate) use pika_cloud::{
+pub(crate) use pika_managed_agent_contract::{
     AgentProvisionRequest, AgentStartupPhase, IncusProvisionParams, ManagedVmProvisionParams,

pika-server previously obtained the agent contract types transitively through pika-cloud. Now it declares a direct dependency on pika-managed-agent-contract and its internal managed_runtime_contract.rs re-export switches the use path from pika_cloud to pika_managed_agent_contract. The pika-cloud dependency is retained for other server-side cloud types.

Switch the CLI to the new crate

Intent: The CLI only needed `pika-cloud` for the agent contract types; replace that dependency entirely.

Affected files: cli/Cargo.toml, cli/src/main.rs

Evidence
@@ -17,7 +17,7 @@ mdk-storage-traits = { workspace = true }
-pika-cloud = { path = "../crates/pika-cloud" }
+pika-managed-agent-contract = { workspace = true }
@@ -14,7 +14,7 @@ use clap::{Args, Parser, Subcommand, ValueEnum};
-use pika_cloud::{AgentProvisionRequest, AgentStartupPhase, IncusProvisionParams};
+use pika_managed_agent_contract::{AgentProvisionRequest, AgentStartupPhase, IncusProvisionParams};

In cli/Cargo.toml the pika-cloud dependency is replaced with pika-managed-agent-contract (workspace reference). The corresponding use statement in cli/src/main.rs is updated to import AgentProvisionRequest, AgentStartupPhase, and IncusProvisionParams from the new crate. This removes the CLI's transitive dependency on everything pika-cloud pulls in.

Switch the Rust SDK to the new crate

Intent: Same rationale as the CLI — the Rust SDK only consumed the agent contract types from `pika-cloud`.

Affected files: rust/Cargo.toml, rust/src/core/agent.rs

Evidence
@@ -26,7 +26,7 @@ keyring-core = { workspace = true }
-pika-cloud = { path = "../crates/pika-cloud" }
+pika-managed-agent-contract = { workspace = true }
@@ -2,7 +2,7 @@ use std::time::Duration;
-use pika_cloud::{AgentProvisionRequest, AgentStartupPhase, IncusProvisionParams};
+use pika_managed_agent_contract::{AgentProvisionRequest, AgentStartupPhase, IncusProvisionParams};

The rust/ SDK crate mirrors the CLI change: pika-cloud is swapped for pika-managed-agent-contract in Cargo.toml, and the import in rust/src/core/agent.rs is rewritten. The SDK no longer has any dependency on pika-cloud.

Diff