Skip to content

Rust SDK

Status: shape-only. The Rust SDK at sdk/rust/src/lib.rs is today a local fixture client that returns shape-correct serde_json::Value responses. It does not make HTTP calls. If you need to talk to the cloud from Rust, use reqwest against the contract directly. A real HTTP Rust client will land alongside the first authentic membrane.

The Rust SDK is most useful for:

  • Embedding Gestalt-shaped reasoning into a Rust binary (a CLI tool, a desktop app, a service) without booting the cloud.
  • Unit testing Rust code that constructs Gestalt envelopes.
  • Verifying fixture receipts in offline contexts.
  • Sharing types with the rest of the workspace (gestalt-core, gestalt-gravity, etc.).

For real cloud integration today, use the TypeScript SDK or call HTTP directly with reqwest and the membrane contract.

If you are inside the workspace:

[dependencies]
gestalt-sdk = { path = "../../sdk/rust" }
serde_json = "1"
use gestalt_sdk::GestaltClient;
let client = GestaltClient::fixture();

The constructor takes no parameters. The client is purely local; no network is involved.

The Rust SDK is intentionally untyped on the response side today. Each method returns a JSON Value shaped like the membrane contract’s response.

use gestalt_sdk::{GestaltClient, IntentPrecheckRequest};
let client = GestaltClient::fixture();
let response = client.precheck_intent(IntentPrecheckRequest {
intent_kind: "invoice.issue".to_string(),
actor_ref: "human_person:anna".to_string(),
effect_class: "economic_action".to_string(),
evidence_refs: vec!["evidence_bundle:invoice_payload".to_string()],
});
assert_eq!(response["operation"].as_str(), Some("intent.precheck"));
assert_eq!(response["fixture"].as_bool(), Some(true));
assert_eq!(response["production_admission"].as_bool(), Some(false));

All defined in sdk/rust/src/lib.rs.

IntentPrecheckRequest
AuthorityResolveRequest
ProofRequest
ProofBundleRequest
PackageTrialRequest
RealityRequest
ZeitgestaltQueryRequest
HumanAuthChallengeRequest
HumanAuthPasskeyVerifyRequest
HumanAuthFaceMatchRequest
M13PresenceApprovalRequest
M13SessionRevokeRequest
M13KeyRotateRequest
EffectIntentRequest
EffectDispatchRequest
EconomicInvoiceRequest
EconomicPaymentObservationRequest
EconomicBookkeepingFactRequest
EconomicPeriodCloseRequest
ConnectorEvidenceIngestRequest
client.precheck_intent(req)
client.resolve_authority_context(req)
client.request_proof(req)
client.request_proof_bundle(req)
client.package_import(req)
client.package_candidate(req)
client.package_activate(req)
client.connector_evidence_ingest(req)
client.connector_evidence_status(tenant)
client.reality_fork(req)
client.reality_diff(req)
client.reality_promote(req)
client.zeitgestalt_query(req)
client.human_auth_challenge(req)
client.human_auth_verify_passkey(req)
client.human_auth_face_match(req)
client.m13_presence_approval(req)
client.m13_session_revoke(req)
client.m13_key_rotate(req)
client.effect_intent(req)
client.effect_dispatch(req)
client.economic_invoice(req)
client.economic_payment_observation(req)
client.economic_bookkeeping_fact(req)
client.economic_period_close(req)
client.m7_state(tenant)
client.verify_fixture_receipt(receipt)

Because the Rust SDK is fixture-only today, decisions are hardcoded based on inputs. Examples:

// resolve_authority_context returns deterministic-fixture matches
// based on target country codes and signal tags
let result = client.resolve_authority_context(AuthorityResolveRequest {
from_country_code: "DE".into(),
target_country_codes: vec!["FR".into()],
signal_tags: vec!["warehouse_country:FR".into()],
evidence_refs: vec![],
});
// result["matched_demands"] includes:
// sovereign_demand:de_registered_office_continuity
// sovereign_demand:eu_intra_union_goods_route
// sovereign_demand:fr_tax_establishment_and_vat
// request_proof refuses without entitlement
let result = client.request_proof(ProofRequest {
subject_ref: "company_geist:foo".into(),
purpose: "advisor_review".into(),
entitlement_ref: None,
fields: vec!["invoice".into()],
});
assert_eq!(result["decision"].as_str(), Some("refuse"));
assert_eq!(result["refusal_reason"].as_str(), Some("missing_entitlement"));
// package_import refuses tampered manifests
let result = client.package_import(PackageTrialRequest {
package_ref: "authority_package:foo".into(),
publisher_signed: true,
reviewer_decision: "approve".into(),
manifest_version: None,
source_hash: None,
content_hash: Some("sha256:tampered".into()),
tampered_manifest: true,
stale: false,
self_activate: false,
});
assert_eq!(result["decision"].as_str(), Some("refuse"));
assert_eq!(result["refusal_reason"].as_str(),
Some("authority_package_tamper_refused"));

These decisions match the cloud’s fixture decisions, so a fixture-mode client and a fixture-mode cloud agree. They are fixture, not real.

use gestalt_sdk::{FixtureReceipt, GestaltClient, fixture_receipt_commitment};
let mut receipt = FixtureReceipt {
receipt_ref: "receipt:fixture".into(),
subject_ref: "intent:fixture".into(),
outcome: "stored".into(),
commitment: String::new(),
};
receipt.commitment = fixture_receipt_commitment(&receipt);
let client = GestaltClient::fixture();
assert!(client.verify_fixture_receipt(&receipt));
receipt.outcome = "tampered".into();
assert!(!client.verify_fixture_receipt(&receipt));

The commitment is sha256(receipt_ref | subject_ref | outcome). This verifies shape integrity, not cryptographic provenance. See ../concepts/receipts-and-proofs.md.

Until the Rust SDK becomes a real HTTP client, use reqwest:

use serde_json::json;
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:3011/v1/intents/precheck")
.bearer_auth("fixture-session-token")
.json(&json!({
"tenant": "tenant_node:rheinwerk_calibration",
"capability": "capability:issue_invoice_fixture_v1",
"action": "issue",
"evidence": ["evidence_bundle:invoice_payload"]
}))
.send()
.await?
.json::<serde_json::Value>()
.await?;

The contract at contracts/gestalt-cloud-membrane.v0.json is the spec. Every operation lists its method, path, and request record.