---
title: Interact with the VRE
framework: Private Cloud Compute Security Guide
role: article
role_heading: Article
path: private-cloud-compute/vreinteraction
---

# Interact with the VRE

Issue requests to and configure the VRE.

## Issue inference requests

Issue inference requests The VRE tooling provides a wrapper you can use to submit an inference request to the PCC software running inside the VRE. To issue an inference request, use this command: % pccvre instance inference-request -N <instance-name> --prompt "<prompt>" Starting with macOS 15.5, pccvre implements additional release-specific inference options when you use recent PCC releases. To explore and use these options, invoke the following commands: % pccvre instance invoke -N <instance-name> --help % pccvre instance invoke -N <instance-name> inference-request --help % pccvre instance invoke -N <instance-name> inference-request --prompt "<prompt>" Behind the scenes, this command connects to the endpoint published by cloudboardd in the VRE — the same endpoint that the PCC Gateway uses to connect to PCC nodes in production. pccvre uses the underlying CloudBoard and TIE application protocols to submit a request and display the response. For example, you might make an inference request that uses both proxy node and inferencing node, as demonstrated in the Create a workload section of the Get Started with the VRE article, with: % pccvre instance \     invoke --name trustedproxy \     inference-request \     --prompt "<prompt>" \     --  --tie-proxy trustedproxy.local \         --hostname inferencenode.local When you make this inference request, the inference-request command prints Apple Silicon Node Attestation generated by the VRE instances, and then the tokens as they are streamed back from the VRE, Request execution log entries, and finally the request summary. Use the inference-request command, when you make an inference request, to print: Apple Silicon Node Attestation generated by the VRE instances Tokens as they are streamed back from the VRE Request execution log entries The request summary Executing inference: {"sepAttestation":"MIIFGzCCBKICAQEwggJMohsEGWZlMDEtYjcwNmRhNzVlMzhjZDUyNy1kLTCjRw ... tie_vre_cli.Apple_Cloudml_Inference_Tie_GenerateResponse: next_token_response {   token: "**\""   token_padding: "M2Wq8..." } ... tie_vre_cli.Apple_Cloudml_Inference_Tie_GenerateResponse: final_response { ... Exercise prefill-decode disaggregation The VRE provides a mechanism to enable Prefill-decode disaggregation between VRE instances. To enable it, you must run a modified workload (see Create a workload) that uses a proxy node and multiple inference nodes: % echo ' {     "instances": [         {             "name": "trustedproxy",             "darwinInitOverrides": {                 "local-host-name": "trustedproxy"             },             "release": "<TIE Proxy release-index>"         },         {             "name": "prefillnode",             "darwinInitOverrides": {                 "local-host-name": "prefillnode"             },             "release": "<TIE release-index>"         },         {             "name": "decodenode",             "darwinInitOverrides": {                 "local-host-name": "decodenode"             },             "release": "<TIE release-index>"         }     ] } ' > vre-configuration.json

% pccvre workload create --configuration vre-configuration.json pccvre workload create instantiates, restores, and configures the instances. The client can explicitly ask for prefill-decode disaggregation in the request, instead of the proxy using heuristics to decide whether to hand off requests from one instance to another between the prefill and decode phases. In PCC, Node selection for requests from proxy nodes; in the VRE, pccvre takes on the role of the PCC Gateway and accepts your chosen PCC nodes as arguments: % pccvre instance \     invoke --name trustedproxy \     inference-request \     --prompt "<prompt>" \     --  --tie-proxy trustedproxy.local \         --ft-leader prefillnode.local \         --et-leader decodenode.local Here, the --ft-leader and --et-leader flags identify the leaders of the prefill-phase and decode-phase ensembles, respectively; the VRE client retains the first token (FT) and extend token (ET) names for these phases. Using this approach, you can see multiple worker node attestations, one for each node participating in request processing, in addition to the inference-request output in the previous example. Use a specific proxy application to serve the request If the proxy instance is configured with multiple concurrent applications as described in Configure concurrent multi-app instances, you can pass the port argument to use a specific proxy application. % pccvre instance \     invoke --name trustedproxy \     inference-request \     --prompt "<prompt>" \     --  --tie-proxy trustedproxy.local \         --hostname inferencenode.local \         --port <proxy-app-port> Exercise KV cache reuse A Multi-Turn Agent is a sequence of related turns in which the server reuses the encrypted key-value cache (KV cache) that one turn produces when it processes the next, avoiding recomputation of tokens the model already processed (see KV cache reuse). Each turn supplies its own key material, so state cached from an earlier turn stays cryptographically inaccessible except while the server processes a turn whose request delivered the matching keys. Use the tie-vre-cli chat command to exercise this flow against a VRE instance running an inference node with the research model (see Create a workload). Each turn carries a session identifier that ties it to the interaction, and the command writes the metadata that each turn returns to the working directory, so a later invocation can continue the same session. Issue the first turn with chat, passing a session identifier of your choice, the model that handles the interaction, and the first prompt. Because no earlier turn exists for the session, the command treats this as the first turn and writes the interaction metadata it returns to a local interaction_<session-id>_<interaction-id>_turn_1.json file: % pccvre instance invoke -N inferencenode \     tie-vre-cli chat \     --session-id 11111111-1111-1111-1111-111111111111 \     --model-bundle-identifier com.apple.fm.language.research.adapter \     --user-prompt "Who wrote Frankenstein?" \     --hostname inferencenode.local Issue the next turn with the same --session-id. The command reads the metadata the previous turn saved, appends the new prompt to the recorded transcript, and forwards the previous turn’s routing hint. Pass the same --hostname, so the turn reaches the node that served the previous turn and the server can reuse that turn’s KV cache instead of recomputing it: % pccvre instance invoke -N inferencenode \     tie-vre-cli chat \     --session-id 11111111-1111-1111-1111-111111111111 \     --model-bundle-identifier com.apple.fm.language.research.adapter \     --user-prompt "When was she born?" \     --hostname inferencenode.local Pass --force-recalculation on a turn to make the server recompute the KV cache rather than reuse it, so you can compare the two paths. Run a multi-turn interaction across two instances You can test multi-turn interactions with two VRE instances: one PCC Agent VRE and one TIE VRE. You submit requests to the PCC Agent VRE with an initial prompt, along with a file containing follow-up prompts, each delimited by a newline character. Start a PCC Agent VRE instance named pccagent_vre (or a name of your choosing). Restore it from a “PCC Agent” release, which you can find by application name in pccvre release list. That release also bundles the TIE Proxy application, so the node acts as the proxy the multi-turn request targets with the --tie-proxy argument in step 4. Start a TIE VRE instance named llm_vre (or a name of your choosing), restored from a “TIE” release. Give the instance a larger amount of memory so you can test KV cache reuse and multi-turn interactions: % /System/Library/SecurityResearch/usr/bin/vrevm modify -N llm_vre --nram 32 Set environment variables referencing the hostnames of the instances created above. If you chose custom instance names in the previous steps, update pccagent_vre and llm_vre accordingly. % PCCAGENT_HOST="$(/System/Library/SecurityResearch/usr/bin/pccvre instance list | grep pccagent_vre | awk '{print $4}')" % LLM_HOST="$(/System/Library/SecurityResearch/usr/bin/pccvre instance list | grep llm_vre | awk '{print $4}')" Submit a multi-turn request targeting the PCC Agent VRE instance. PCC Agent invokes the Multi-Turn Agent, which issues a series of requests to the LLM VRE. % echo -e "How are you?\nHow is your day?" > prompts.txt % pccvre instance invoke --name pccagent_vre \ tie-vre-cli \ --payload '{"model_config":{"options":{"max_tokens":5}, "inference_id": "com.apple.fm.language.research.adapter"},"multi_turn_metadata":{"force_recalculation":false, "session_id":"11111113-1113-495A-93FC-0C247A3E6E5F", "interaction_id":"10000002-1001-1111-93FC-0C247A3E6E5F"}}' --user-prompt "hello" \ --workload-parameters '{"inference-id": ["com.apple.fm.language.instruct_server_v2.lw_planner_v4"]}' \ --parse-as-generate-request true \ --request-bypass false \ --tie-proxy "$PCCAGENT_HOST" \ --hostname "$LLM_HOST" \ --follow-up-prompts prompts.txt \ --workload-type "pcc-agent" In this request, model_config.inference_id (com.apple.fm.language.research.adapter) is the model the LLM node runs for each turn, and the inference-id in --workload-parameters (com.apple.fm.language.instruct_server_v2.lw_planner_v4) is the planner PCC Agent uses to drive the interaction. With force_recalculation set to false, each turn reuses the KV cache; setting it to true makes each turn recompute its context instead. Inspect diagnostic logging The VRE can forward five kinds of diagnostic data to a collector: logs, crash reports, panic reports, security events, and metrics. You can configure the VRE to forward this diagnostic data to a local collector, using the darwin-init configurations provided below. In these examples, <ip> is the IP address and <port> is the port of your collector. Enable log, crash, and panic forwarding This configuration instructs splunkloggingd in the VRE to forward crash logs, panic logs, and allowed log lines that match the provided predicate: "secure-config": {   "com.apple.logging.policyPath": "/private/var/PrivateCloudSupport/opt/audit-lists/customer/",   "com.apple.logging.logFilteringEnforced": true,   "com.apple.logging.crashRedactionEnabled": true }, "preferences": [   {     "key": "Predicates",     "value": [       "process == \"cloudboardd\""     ],     "application_id": "com.apple.prcos.splunkloggingd"   },   {     "key": "Index",     "value": "<index name>",     "application_id": "com.apple.prcos.splunkloggingd"   },   {     "key": "Server",     "value": "http://<ip>:8088",     "application_id": "com.apple.prcos.splunkloggingd"   },   {     "key": "Token", // optional     "value": "<token val>",     "application_id": "com.apple.prcos.splunkloggingd"   } ] Additionally, please note: Predicates: Replace cloudboardd with the process of interest. You can use an “always true” predicate such as "foo" == "foo" to forward all allowed logs. See man log for more help with predicates. Token: Optional key. If your collector requires a token, include it here to have it piped through to the log forwarder. Index: Required. If your collector requires an index (such as Splunk), put the index here. If not, then put any string value. You can also specify each of these keys with an additional Prism prefix to configure an optional second destination with its own predicate. Enable security events "secure-config": {   "com.apple.securitymonitorlited.serverURL" : "http://<ip>:8088" } The above configuration overrides the destination for security events. Every secure-config security policy respects this setting, including customer. Enable metrics submission {   "application_id" : "com.apple.acdc.cloudmetricsd",   "key" : "DefaultDestination",   "value" : {     "Namespace" : "namespace",     "Workspace" : "workspace"   } }, {   "application_id" : "com.apple.acdc.cloudmetricsd",   "key" : "Destinations",   "value" : [     {       "Clients" : [       ],       "Namespace" : "namespace",       "PublishInterval" : 60,       "Workspace" : "workspace"     }   ] }, {   "application_id" : "com.apple.acdc.cloudmetricsd",   "key" : "OpenTelemetryEndpoint",   "value" : {     "DisableMtls" : true,     "Hostname" : "<ip>",     "Port" : <port>   } }, {   "application_id" : "com.apple.acdc.cloudmetricsd",   "key" : "UseOpenTelemetryBackend",   "value" : true }, {   "application_id" : "com.apple.acdc.cloudmetricsd",   "key" : "LocalCertificateConfig",   "value" : { } } The above configuration enables cloudmetricsd to submit metrics data to the provided host and port. Configure a collector Logs, crash reports, panic reports, and security events are all forwarded using the Splunk HEC protocol. You can configure any collector that supports this protocol — such as Splunk, Vector, or OpenTelemetry Collector — to receive and display these events. Metrics are forwarded using Open Telemetry Line Protocol (OTLP) and require a collector that can accept OTLP events. Using the OpenTelemetry Collector’s splunk-hec module can enable receiving events sent over both the Open Telemetry Line Protocol (OTLP) and Splunk HEC protocols. To use this module to receive events from the VRE, start by downloading otelcol-contrib from a release of opentelemetry-collector-contrib. Then construct a configuration (otel.yaml) as follows: receivers:   splunk_hec:     endpoint: "0.0.0.0:8088"     access_token_passthrough: true   otlp:     protocols:       grpc:         endpoint: "0.0.0.0:8089"

processors:

exporters:   debug:     verbosity: normal

service:   pipelines:     logs:       receivers: [splunk_hec]       exporters: [debug]     metrics:       receivers: [otlp]       processors: []       exporters: [debug] This configuration enables receiving all of the types of diagnostic data listed above. You can find more details on configuring the output of the debug exporter and splunkhecreceiver at their respective repositories. You can then launch the collector as follows: % ./otelcol-contrib --config otel.yaml If you configured the VRE instance to emit diagnostics, events print out to stdout. Inspect an attestation bundle You can inspect Apple Silicon Node Attestation of PCC production nodes, as well as VRE instances. Use the Appendix: Apple Intelligence Report to view attestations of PCC production nodes. Issue an inference request against a VRE instance to view its attestation bundle. Use pccvre attestation parse to display the contents of an attestation bundle, including its SEP attestation, sealed hash ledger, application data, and transparency proofs. Use pccvre attestation canonicalize to generate a Release data structure from an attestation bundle. Note that releases generated using the VRE don’t match PCC node releases due to differences in SoC identifiers, virtualized kexts, and demo model. Use pccvre attestation canonicalize --detail and pccvre release dump --detail to print Appendix: Apple Silicon Secure Boot Tags of tickets in a release structure and compare releases. Use pccvre attestation verify to verify an attestation using the host’s CloudAttestation framework. For VRE attestations to be successfully verified, the following flags must be set: The pccvre attestation subcommands accept attestation bundles in several input formats: apple-intelligence-report — the default input format — reads an Apple Intelligence Report and uses the --request-index and --attestation-index arguments to select a specific attestation bundle within the report. attestation-bundle:protobuf format accepts both binary and Base64-encoded Protobuf attestation bundles. attestation-bundle:json format accepts the JSON representation of an attestation bundle. note: --input-format apple-intelligence-report in pccvre attestation subcommands requires macOS 26.4. Validate transitive trust When you make inference requests against VRE instances using the pccvre instance invoke -N <instance-name> inference-request command, the output contains both node attestations that the user’s device receives and Request execution log (REL) entries. These REL entries contain attestation bundles of transitively trusted nodes from when TIE Proxy was in use, for example: Proxy attestation:     release digest: 2c43734a192c7f423fc7d4dcf73903428bffc253909e0ae808f11f64edcffeb0     trusted release set: []     {"sepAttestation":"MIIFQTCCBMYCAQEwggJwoSIEIMyWzhPfc9lm3TeCxEU6iOFtwLo1vbaaLb... ... Request execution log entry:     is NACK: false     is final: false     associated proxy attestation:         release digest: 2c43734a192c7f423fc7d4dcf73903428bffc253909e0ae808f11f64edcffeb0     compute node attestation:         release digest: de8ed97fa5d4b0ee326e2834b0399f2ed89444fc7db1a38abb7a16a1ef85a7f3         {"sepAttestation":"MIIFHDCCBKICAQEwggJMohsEGWZlMDEtYmNmNWM4YjFlZGY4ZDFhYy1kLT... ... Request execution log entry:     is NACK: false     is final: true     associated proxy attestation:         release digest: 2c43734a192c7f423fc7d4dcf73903428bffc253909e0ae808f11f64edcffeb0 The above example illustrates three types of entries a user’s device sees when using a proxy node: The attestation of the proxy itself, which anchors the Trusted log revisions for proxied worker nodes. Request execution log entries, each containing the selected worker node’s release digest as well as complete attestation. The final REL entry for the request, signaling that the proxy is sending no further requests to other PCC nodes. A proxy node validates each worker node’s attestation against the trusted log revision its own attestation anchors. A VRE release loosens that enforcement by setting the com.apple.pcc.research.disableAppleInfrastrucutureEnforcement secure-config parameter on the proxy. A node accepts that parameter only in a virtual machine, and its attestation names the security policy that governed its boot. Restrict proxy transitive trust A proxy node sends requests to an inference node only while the transparency log, at the revision the proxy’s own attestation anchors, includes the inference node’s release digest. The com.apple.cloudboard.attestation.enableTransitiveProofVerification secure-config key governs this check. To watch a proxy reject a worker, create a Create a workload holding a proxy instance and an inference instance, issue an inference request through the proxy, and then change the software the inference node runs. Enabling SSH on the inference node, for example, adds a cryptex to its release: the node’s release digest changes, the proxy no longer accepts its attestation, and inference fails. Load custom cryptexes Use cryptexes to create and package additional software to install on a VRE instance. The pccvre tool provides a command to create a new cryptex from a specified directory structure: % pccvre cryptex create --source CustomCryptexRootDirectory --variant MyCustomCryptex Created new cryptex at path: MyCustomCryptex.aar with variant name: MyCustomCryptex When such a cryptex is installed in VRE, its content is mounted at /private/var/PrivateCloudSupportInternalAdditions/. pccvre cryptex create marks packaged binaries as allowed in Restricted Execution Mode. Binaries installed with a custom cryptex must have a code signature; ad-hoc signing is sufficient. The cryptex variant is an identifier string that must be unique within a VRE instance. pccvre provides helpers to easily list and modify the set of cryptexes configured for a VRE instance: % pccvre instance configure cryptex list -N <instance-name> Configured cryptexes: - FM_LANGUAGE_SECURITY_RESEARCH_V1 - PrivateCloud Support % pccvre instance configure cryptex remove -N <instance-name> -V PrivateCloudSupport Removed cryptex matching 'PrivateCloudSupport' from VRE instance. % pccvre instance configure cryptex list -N vre Configured cryptexes: - FM_LANGUAGE_SECURITY_RESEARCH_V1 % pccvre instance configure cryptex add -N <instance-name> -C "MyCustomCryptex:$PATH_TO_MY_CUSTOM_CRYPTEX" Added cryptex 'MyCustomCryptex' to VRE instance. Execute binaries in a cryptex The executables present in a cryptex may link libraries and frameworks also present in the cryptex. To enable dyld to find these libraries and frameworks, you must run the executable with the cryptexctl exec command to set an appropriate subsystem_root_path value that informs dyld of the relevant search paths: % cryptexctl exec /private/var/PrivateCloudSupportInternalAdditions/ /private/var/PrivateCloudSupportInternalAdditions/$PATH_TO_EXECUTABLE In this example, the binary at $PATH_TO_EXECUTABLE is able to link libraries and frameworks located relative to /private/var/PrivateCloudSupportInternalAdditions/. Any children of that process automatically inherit the configuration. This step is needed only when running such executables manually, such as through ssh, as cryptexd automatically handles it when loading LaunchDaemons contained within a cryptex. Disable Restricted Execution Mode Restricted Execution Mode (REM) enables the system to lock out functionality that’s required only during the system’s initial boot and setup. Entering REM is enforced by TXM to be a one-way transition switch, after which the TXM refuses to load additional trust caches and imposes new constraints on code execution. By default, the darwin-init configuration for the VRE configures REM the same way as actual PCC nodes — {"userspace-reboot": "rem"}. After setup is complete, darwin-init initiates a user-space reboot, and launchd makes a system call to request TXM to activate the one-way REM switch. This process limits the set of executables that can run after entering REM to those in the loaded trust caches. On the VRE, you can change the darwin-init configuration to {"userspace-reboot": "rem-dev"}. This change configures the VRE to forgo making a system call to TXM to activate the one-way REM switch after the user-space reboot, which allows you to use tools that are normally restricted by REM. Debug the kernel You can debug the kernel by attaching to the GDB stub of a VRE instance. pccvre instance start prints the GDB stub port: % pccvre instance start --name vre ... GDB stub available at localhost:59013 Restore custom firmware The PCC VRE supports restoring an instance with custom firmware for the kernel cache, SPTM, and TXM images. To see further documentation for these options, invoke pccvre instance create --help. All system firmware is packed as an Image4 payload (.im4p) file. The pccvre image4 extract command provides the functionality to extract binary payloads from the Image4 file. Conversely, the pccvre image4 package command provides the functionality to package a binary payload into an image4 wrapped payload for the specified firmware. To see further documentation for these commands, invoke pccvre image4 --help. Interact with the control-plane agent Apple provides a PCC control-plane testing server that you can run on your host to interact with the controlplaneagent daemon, discussed in ServiceControl framework, which runs in the VRE instance. The pccvre tool provides a subset of commands to facilitate the use of the control-plane testing server. To explore them, invoke the following command: % pccvre instance invoke -N <vre-instance> control-plane --help The setup command registers a port on your host for the control-plane testing server to listen on, and configures the controlplaneagent to connect to that port: % pccvre instance invoke -N <vre-instance> control-plane setup --port <port> After the setup, restart the VRE instance so controlplaneagent loads the new configuration. Next, start the control-plane testing server: % pccvre instance invoke -N <vre-instance> control-plane server After the controlplaneagent connects to the control-plane testing server, you can exercise the controlplaneagent functionalities by invoking the send command. Behind the scenes, the send command uses the control-plane testing server to provide the specified command when the controlplaneagent next requests a command. % pccvre instance invoke -N <vre-instance> control-plane send <command> This example exercises TIE model switching through the control plane. Note that the init command, which asks the controlplaneagent to manage the specified service, is required to run only once for that service: % pccvre instance invoke -N <vre-instance> control-plane send init --service "com.apple.tie-controllerd.from.control-plane-agent" % pccvre instance invoke -N <vre-instance> control-plane send deactivate --service "com.apple.tie-controllerd.from.control-plane-agent" % pccvre instance invoke -N <vre-instance> control-plane send model-switch --service "com.apple.tie-controllerd.from.control-plane-agent" --model "com.apple.fm.language.research.partial_grammar#cv10" % pccvre instance invoke -N <vre-instance> control-plane send activate --service "com.apple.tie-controllerd.from.control-plane-agent" Exercise cloud asset distribution To exercise Cloud asset distribution, you can set the following configuration: "secure-config": {   "com.apple.cloudos.cloudassetdownloaderd.enabled": true,   "com.apple.cloudos.cloudassetdownloaderd.useControlPlaneAgent": true } If the asset you want to test is not in AEA format, set the following additional configuration: "secure-config": {   "com.apple.cloudos.cloudassetdownloaderd.allowNonAEAAssets": true } First set up and start the control-plane testing server as described in Interact with the control-plane agent: run control-plane setup, restart the instance, then start control-plane server. Then use control-plane send apply to provide the cloud asset configurations to cloudassetdownloaderd; the map takes effect only once controlplaneagent is polling the server: % pccvre instance invoke -N <vre-instance> control-plane send apply \     --service "com.apple.cloudos.cloudassetdownloaderd" \     --key "applicationAssetMap" \     --value '{"CipherMLAssets":[{"url":"http://<assets-server-host>:<assets-server-port>/test-v1.aar","version":"1","asset_id":"testAsset"}]}' cloudassetdownloaderd adopts a given asset map once. Re-sending an identical applicationAssetMap is a no-op that triggers no new download, so to exercise the download again, change the version or asset_id. You can use pccvre http-server to host your test assets. Run the command with your asset directory; it then prints the server’s IP address and port for use in the configuration above. % pccvre http-server <directory> 192.168.64.1:49516 To verify your assets are being loaded, you can SSH into the VRE instance and use the log show command to look at the cloudassetdownloaderd logs: % log show --info --predicate 'subsystem=="com.apple.cloudos.cloudassetdownloader"' Received new asset configs to apply: [applicationID: CipherMLAssets, assetID: testAsset, source: http://192.168.64.1:49516/test-v1.aar, destination: /private/var/mobile/assetdownloader/CipherMLAssets/testAsset/1, version: 1] Asset processed successfully. Source=http://192.168.64.1:49516/test-v1.aar Destination=/private/var/mobile/assetdownloader/CipherMLAssets/testAsset/1 Exercise external tool calling PCC Agent invokes Appendix: Tool Gateway Protocol through cb_bridged, which connects to a tool gateway: an external gRPC service hosted outside the PCC trust boundary. You can exercise this path in the VRE. Set up the agent and compute VRE instances This example uses two VRE instances: Run a mock tool gateway MockToolGateway ships as part of the PCC tools. Use the pccvre instance invoke tool subcommand, a trampoline for running other tools from the PCC tools directory on the host: % pccvre instance invoke --name pccagent tool MockToolGateway --host 0.0.0.0 --port 50051 MockToolGateway implements the PccToolGateway gRPC service and replies to every tool call with a basic response, so you can exercise the connection and protocol without a real tool implementation. Connect the agent to the mock gateway Add the following secure-config overrides to the pccagent instance’s darwin-init configuration (see Create a workload), replacing <host-ip> with an address the VRE guest can reach on your host. MockToolGateway serves without TLS, so you must set tlsConfig.enable to false. "secure-config": {   "com.apple.cloudboard.cb_bridged.toolGateway.targetHost": "<host-ip>",   "com.apple.cloudboard.cb_bridged.toolGateway.targetPort": 50051,   "com.apple.cloudboard.cb_bridged.toolGateway.tlsConfig.enable": false } Restart the agent instance so cb_bridged loads the new configuration. Script the shadow responses To fully control the tool call, you need two shadow response scripts: a tool call request and a final inference answer. Responses need to adhere to the correct protocol; the Minimal response protocol helps you do this. Example tool call request: tool_call.txt call {   call_id: "call_1"   content {     function {       tool_name: "web_search"       arguments: "{\"search_queries\": [\"current weather in Cupertino\"]}"     }   } } Example final answer: final_answer.txt content {   tokens: "The current weather in Cupertino is 68°F and sunny." } Example terminating response: final_response.txt final_response {   sentence: "The current weather in Cupertino is 68°F and sunny." } Encode each response using protoc, the protobuf compiler, piping through the base64 command, and capture the result in a variable named for the response it encodes: (The final answer script also needs to send inference_complete and final_response responses to correctly terminate the request. Give final_response a sentence; an empty one leaves the client waiting until it times out.) % tool_call_data=$(protoc --encode Response response.proto <<< "$(cat tool_call.txt)" | base64) % final_answer_data=$(protoc --encode Response response.proto <<< "$(cat final_answer.txt)" | base64) % inference_complete_data=$(protoc --encode Response response.proto <<< "inference_complete {}" | base64) % final_response_data=$(protoc --encode Response response.proto <<< "$(cat final_response.txt)" | base64) Create each script JSON file from these variables: % cat > tool_call.json <<EOF {   "lines": [     { "response": { "data": "$tool_call_data" } },     { "finishResponse": {} }   ] } EOF % cat > final_answer.json <<EOF {   "lines": [     { "response": { "data": "$final_answer_data" } },     { "response": { "data": "$inference_complete_data" } },     { "response": { "data": "$final_response_data" } },     { "finishResponse": {} }   ] } EOF cloudboard-vre-cli shadowRemote accepts multiple script files and serves them round-robin. It ships with the release’s PCC tools, so run it on the host through pccvre instance invoke, passing both files in order: % pccvre instance invoke -N inference tool cloudboard-vre-cli shadowRemote \     tool_call.json final_answer.json --host 0.0.0.0 --port 8080 --log-level warn Add the following secure-config to the inference instance’s darwin-init configuration, replacing <host-ip> with your host’s address on the VM network, which is 192.168.64.1 for the default NAT configuration: "secure-config": {   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.enabled": true,   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.remoteHost": "<host-ip>",   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.remotePort": 8080,   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.workloadName": "tie-cloudboard-apple-com",   "com.apple.cloudboard.skipMultiAppValidations": true } Make a tool-calling inference request PCCAgentApp only routes a tool call to cb_bridged if the request declares that tool as a server tool capability up front. Add a tool_constraints entry naming the tool to the request payload when making the inference request. A web_search capability declaration requires country_code, and PCCAgentApp rejects a request that omits it. Omitting the capability declaration entirely causes PCCAgentApp to reject the eventual tool call before it reaches cb_bridged. You also need to pass the IP addresses or hostnames and port in the --tie-proxy, --hostname, and --port options: % pccvre instance \     invoke --name pccagent \     tie-vre-cli inference \     --tie-proxy <agent node ip or hostname> \     --hostname <inference node ip or hostname> \     --workload-type pcc-agent \     --request-bypass false \     --user-prompt "<prompt>" \     --workload-parameters '{"inference-id":["<inference-id>"]}' \     --payload '{"model_config":{"inference_id":"<inference-id>","options":{"tool_constraints":{"tool_capabilities":[{"web_search":{"locale":"en_US","country_code":"US"}}]}}}}' Four of these options are required for the tool call to reach cb_bridged: Choose an inference identifier whose feature declares no safety guardrails, such as com.apple.fm.language.instruct_server_v2.open_ended_compose. Guardrails make their own inference calls to the same instance, and because the shadow remote serves its scripts in round-robin order, a guardrail call consumes the tool call script before the request that needs it. MockToolGateway logs each connection, request, and response to standard output. A successful run logs the MCP handshake followed by a tools/call entry, and tie-vre-cli prints the tool call and then the final answer. PCCAgentApp maps the web_search server tool to the gateway-side tool pegasus_search, and rewrites the model’s search_queries array into a single query argument alongside locale and country_code, so the gateway sees: {     "jsonrpc": "2.0",     "id": "<tool-invocation-id>",     "method": "tools/call",     "params": {         "name": "pegasus_search",         "arguments": {             "query": "current weather in Cupertino",             "locale": "en_US",             "country_code": "US"         }     } } Exercise HomeKit Secure Video Analysis The HomeKit Secure Video Analysis (HKSV) workflow generates natural-language video descriptions and embeddings for HomeKit Secure Video clips, coordinating a PCC Agent instance, a media decoder, an embedding worker, and an LLM. You can exercise this workflow in the VRE. Set up the agent and compute VRE instances This example uses four VRE instances: You configure the LLM node with shadowing because the LLM that ships with the VRE can’t take image inputs, which the HKSV analysis workflow requires for captioning. PCC Agent VRE For this node, use a “PCC Agent” release; no changes are required. Media decoder VRE For this node, use a “PCC MediaDecode” release. To replicate the Jetsam settings of a production MediaDecode node, apply this change to the darwin-init: % pccvre instance configure \     darwin-init dump --name mediadecode_vre \     | jq '(.cryptex[] | select(.variant == "PCCApp_MediaDecode")) += {"jetsam_properties_variant": "s1"}' \     > /tmp/mediadecode_vre-darwin-init.json % pccvre instance configure darwin-init set --name mediadecode_vre --input /tmp/mediadecode_vre-darwin-init.json Embedding worker VRE For this node, use a “PCC Agent Worker Embedding” release. LLM VRE The following procedure adapts a TIE compute instance (with TIECloudApp enabled) to serve a captioning response using the shadow app. The HKSV workflow reads the caption from both the streamed response content tokens and the terminating final_response sentence, so a script that populates only one of them returns empty captions. Provide the same caption JSON in a content token and in a final_response, and close the token stream with an inference_complete message between them. Example caption content: content.txt content {   tokens: "{\"short_caption\":\"Test caption\",\"full_caption\":\"This is a full caption.\",\"noteworthy\":1,\"is_sensitive\":false,\"is_no_activity\":false}" } Example terminating response: final_response.txt final_response {   sentence: "{\"short_caption\":\"Test caption\",\"full_caption\":\"This is a full caption.\",\"noteworthy\":1,\"is_sensitive\":false,\"is_no_activity\":false}" } The protobuf schema is defined here: Appendix: TIE Response Protocol. Encode the caption content, the inference_complete message that closes the token stream, and the terminating final_response, using protoc, the protobuf compiler, piping through the base64 command, and capture each in a variable: % content_data=$(protoc --encode Response response.proto <<< "$(cat content.txt)" | base64) % inference_complete_data=$(protoc --encode Response response.proto <<< "inference_complete {}" | base64) % final_response_data=$(protoc --encode Response response.proto <<< "$(cat final_response.txt)" | base64) Create a shadow app script JSON file that serves the caption content, then the terminating messages: % cat > responses.json <<EOF {   "lines": [     { "response": { "data": "$content_data" } },     { "response": { "data": "$inference_complete_data" } },     { "response": { "data": "$final_response_data" } },     { "finishResponse": {} },     { "wait": { "milliseconds": 2000 } }   ] } EOF Start the shadow remote server on the host, using the cloudboard-vre-cli that ships with the release’s PCC tools: % pccvre instance invoke -N llm_vre tool cloudboard-vre-cli shadowRemote \     responses.json --host 0.0.0.0 --port 8080 --log-level warn Add the following secure-config to the llm_vre instance’s darwin-init configuration, replacing <host-ip> with your host’s address on the VM network, which is 192.168.64.1 for the default NAT configuration: "secure-config": {   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.enabled": true,   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.remoteHost": "<host-ip>",   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.remotePort": 8080,   "com.apple.cloudboard.cloudApp.TIECloudApp.shadow.workloadName": "tie-cloudboard-apple-com",   "com.apple.cloudboard.skipMultiAppValidations": true } Make an HKSV analysis request Use the following command to make a request with an HKSVFragment H.264 or H.265 video, as described in HomeKit Secure Video Analysis: % pccvre instance \     invoke --name pccagent_vre \     tie-vre-cli hksv \     --tie-proxy <agent node ip or hostname> \     --media-decode-node <media decode node ip or hostname> \     --embedding-node <embedding worker node ip or hostname> \     --llm-node <llm node ip or hostname> \     --log-routing \     --video-path <video fragment file> You can add more fragments to the request by adding --video-path options at the end. Each fragment can be no longer than 10 seconds. The CLI logs the entire response to standard output. If the workflow succeeds, the output contains embeddings and captions. Exercise Visual Lookup The Visual Lookup (VLU) workflow matches an image embedding against a database of visual entities that lives outside the PCC trust boundary, retrieving the candidate cluster with Private Information Retrieval (PIR). The pcc-vre-pir-service repository provides vrepir, a test server that stands in for the external PIR server, together with the tools that build a PIR-ready database from sample entity data. You can exercise the whole retrieval path in the VRE. Set up the agent and worker VRE instances This example uses two VRE instances: Create both instances as a Create a workload, replacing <host-ip> with an address the VRE guest can reach on your host, which is 192.168.64.1 for the default NAT configuration: % echo ' {     "instances": [         {             "name": "pcc-agent",             "darwinInitOverrides": {                 "local-host-name": "pcc-agent",                 "preferences": [                     {                         "application_id": "com.apple.cloudos.cb_jobhelper",                         "key": "EnablePIR",                         "value": false                     }                 ],                 "secure-config": {                     "com.apple.cloudos.PCCAgentKit.RemoteTools": "PIRTool",                     "com.apple.cloudboard.skipMultiAppValidations": true                 }             },             "release": "<PCC Agent release-index>"         },         {             "name": "pcc-agent-worker",             "darwinInitOverrides": {                 "local-host-name": "pcc-agent-worker",                 "preferences": [                     {                         "application_id": "com.apple.cloudos.cb_jobhelper",                         "key": "EnablePIR",                         "value": true                     }                 ],                 "secure-config": {                     "com.apple.cloudboard.cb_bridged.pirService.serviceURL": "http://<host-ip>:5555"                 }             },             "release": "<PCC Agent Worker release-index>"         }     ] } ' > vre-configuration.json

% pccvre workload create --configuration vre-configuration.json Three settings drive the split between the nodes: The repository ships this configuration as vre-configuration.json. Use pccvre release list to find the “PCC Agent” and “PCC Agent Worker” release indices. Build the entity database and package it as a cryptex Build the tools, then turn the sample entity documents in input.json into a clustered database and process that database for PIR: % swift build -c release --product vrepir % swift build -c release --product SimplePIRProcessDatabase % mkdir output % ./.build/release/vrepir process input.json art output % ./.build/release/SimplePIRProcessDatabase config.json vrepir process runs k-means clustering over the sample documents to build the Visual entity database VLU searches: the cluster codebook, the cluster index, and the stash (written to big_clusters.bin, and empty for the sample data). It also writes a per-entity metadata table VLU uses to Request flow. SimplePIRProcessDatabase, which comes from swift-homomorphic-encryption, turns the cluster index into the PIR shards the server hosts, along with the hints and parameters the node needs. In production, Cloud asset distribution delivers these node-side assets to the worker node: the codebook, stash, and per-entity metadata, together with the PIR hints and parameters. For this workflow, package them as a cryptex and add it to the worker instance: % mkdir -p CipherMLAssets/encryptedVluArt % cp output/{asset_metadata.bin,big_clusters.bin,embedding_codebook.binpb,pir-db-*.hint.bin,pir-db.config.binpb} \     CipherMLAssets/encryptedVluArt % pccvre cryptex create --source CipherMLAssets --variant CipherMLAssets \     --mount-point /private/var/CipherMLAssets % pccvre instance configure cryptex add -N pcc-agent-worker -C CipherMLAssets:CipherMLAssets.aar Run the test PIR server Start both instances, and wait for them to finish booting: % pccvre instance start --name pcc-agent --name pcc-agent-worker The host’s bridge interface exists only while an instance is running, so start the test server after the instances. Pass the processed-database directory and the PIR parameters, and bind to the same host address you configured as the service URL: % ./.build/release/vrepir serve output output/pir-db.config.binpb --host <host-ip> The server prints the address it binds to, then answers EncryptedVisualSearch queries by running the homomorphic PIR computation over the processed database, without learning the target cluster or the response contents (see Security properties). Make a Visual Lookup request Issue a request against the agent instance, passing an embedding of the same dimension as the documents in input.json: % pccvre instance \     invoke --name pcc-agent \     tie-vre-cli \     --payload '{"echo_agent_request": { "msg": "{\"index\":\"encryptedVluArt\", \"embedding\": [0, 1, 0]}" }}' \     --tie-proxy pcc-agent.local \     --hostname pcc-agent-worker.local \     --workload-parameters '{"inference-id": ["com.apple.fm.service.vlu.v1"]}' \     --parse-as-generate-request false \     --request-bypass false --workload-parameters selects the workflow the agent dispatches to, and --request-bypass false lets the agent node’s own cloud app receive the request data. A successful run returns the best-matching entries with their resolved localized titles, alongside the ranked candidates from the retrieved cluster: {"results":[{"title":"Pepper","docId":"Q141"}, ...],"candidateKnowledgeIds":[...],"domain":"art"} To watch the retrieval path from inside the node, Enable SSH on the worker instance and stream the CipherMLSE logs: % log stream --info --predicate 'subsystem == "com.apple.ciphermlse"' cb_jobhelper logs each stage of the query: searching the codebook for the nearest centroid, submitting the query for the selected cluster, and decrypting the response it gets back. note: pcc-vre-pir-service swift-homomorphic-encryption Exercise recitation prevention PCC Agent’s Recitation prevention mechanism detects and blocks model output that reproduces content verbatim, by looking up output fingerprints in the Private Filter Service (PFS). You can exercise this flow in the VRE to see it filter responses and emit a block. Set up the agent, inference, and PFS VRE instances This example uses three VRE instances: Create the three instances as a Create a workload: % echo ' {     "instances": [         {             "name": "pccagent",             "darwinInitOverrides": {                 "local-host-name": "pccagent"             },             "release": "<PCC Agent release-index>"         },         {             "name": "inferencenode",             "darwinInitOverrides": {                 "local-host-name": "inferencenode"             },             "release": "<TIE release-index>"         },         {             "name": "pfs",             "darwinInitOverrides": {                 "local-host-name": "pfs"             },             "release": "<Private Filter Service release-index>"         }     ] } ' > vre-configuration.json

% pccvre workload create --configuration vre-configuration.json The PFS instance requires jetsam properties for its cryptex to start. Apply this change to the PFS instance’s darwin-init configuration: % pccvre instance configure \     darwin-init dump --name pfs \     | jq '(.cryptex[] | select(.variant == "PCCApp_TrustedProxy")) += {"jetsam_properties_variant": "pfs-s1"}' \     > /tmp/darwin-init-pfs.json % pccvre instance configure darwin-init set --name pfs --input /tmp/darwin-init-pfs.json The PCC Agent instance’s client router discovers the PFS instance through Appendix: PCC Application Identifiers. Run the service-discovery setup command against the PCC Agent and PFS instances to register them with a local ServiceDiscovery test server: % pccvre instance invoke --name pccagent service-discovery setup % pccvre instance invoke --name pfs service-discovery setup Next, start the ServiceDiscovery test server on your host: % pccvre instance invoke --name pccagent tool ServiceDiscoveryTestServer --hostname 0.0.0.0 Then start the PCC Agent, inference, and PFS instances, and watch the test server’s output until both the PCC Agent and PFS instances register. Make an inference request Issue an inference request against the PCC Agent instance: % pccvre instance \     invoke --name pccagent \     tie-vre-cli \     --payload '{         "prompt_template": {             "prompt_template_v1": {                 "prompt_template_id": "com.apple.gm.instruct.genericChat",                 "prompt_template_variable_bindings": [                     {"name": "userPrompt", "value": "<prompt>"}                 ]             }         },         "model_config": {             "options": {"max_tokens": 200},             "tokenizer_name": "com.apple.fm.language.research.tokenizer",             "model_name": "com.apple.fm.language.research.base",             "model_adapter_name": "com.apple.fm.language.research.adapter"         }     }' \     --workload-parameters '{"inference-id": ["com.apple.fm.language.research.adapter"]}' \     --workload-type "pcc-agent" \     --parse-as-generate-request true \     --request-bypass false \     --tie-proxy pccagent.local \     --hostname inferencenode.local If the response is not blocked, it includes both the generated content and recitation metrics, such as the filter-lookup and fuzzy-match latencies. Simulate a recitation block To simulate a block, raise the false-positive rate of the keyed Bloom filter that the PFS instance generates for the research model to a high value, such as 0.99, by setting com.apple.privatefilter.fakeFilter.com.apple.fm.language.research.base.bf2.fpr in the PFS instance’s secure-config: % pccvre instance configure \     darwin-init dump --name pfs \     | jq '."secure-config"."com.apple.privatefilter.fakeFilter.com.apple.fm.language.research.base.bf2.fpr" = 0.99' \     > /tmp/darwin-init-pfs.json % pccvre instance configure darwin-init set --name pfs --input /tmp/darwin-init-pfs.json Restart the PFS instance so it regenerates the filter with the new false-positive rate, and wait for it to register with the test server again. The inflated false-positive rate makes the fingerprint lookup report a hit on any output. Reissuing the same inference request now triggers a block, returned as a recitation-rejection error, unless the output overlaps closely enough with the input for the fuzzy-matching algorithm to ignore the hit. Exercise safety overrides PCC Agent’s Safety overrides reject request or response content that matches a set of regular-expression patterns delivered as a cloud asset. You can exercise both directions in the VRE: author your own override asset, serve it to the VRE through cloud asset distribution, and then issue a request that matches one of your patterns. The steps below follow that path from end to end with a single inference ID and a pattern of your own. This example uses two VRE instances: Create them as a Create a workload, as the other examples in this article do. Author the override metadata Create one directory per inference ID and direction, suffixed .input or .output, each holding a metadata.json. This walkthrough uses one inference ID throughout, com.apple.fm.language.instruct_server_v2.lw_planner_v3. Within each resource directory, the metadata sits under a version subfolder: overrides/     com.apple.fm.language.instruct_server_v2.lw_planner_v3.input/         v9/             metadata.json     com.apple.fm.language.instruct_server_v2.lw_planner_v3.output/         v9/             metadata.json The flattened form, with metadata.json directly inside each resource directory, is also accepted. PCC Agent resolves each resource by the request’s inference ID plus the direction suffix, so an asset applies only to requests whose inference ID matches a resource the asset defines. Use the same ID when you send the request in the last step, or PCC Agent won’t consult the asset you author here. Give the input and output rules different terms. Otherwise, a prompt that asks the model to emit that shared term matches the input rule and never reaches the response stream, because the input check runs first. This walkthrough uses BLOCKME on input and ECHOME on output. Each metadata.json carries up to four fields, and omitted fields default to an empty list or zero: The .input resource, rejecting a prompt that contains the input term: { "regexReject": ["\\bBLOCKME\\b"] } The .output resource, in signaling form, which fires after content starts streaming: {     "regexReject": ["\\bECHOME\\b"],     "windowSize": 6 } The .output resource, in prevention form, which holds tokens and blocks before emission. Use one form or the other, not both: {     "regexRejectStrict": ["\\bECHOME\\b"],     "windowSizeStrict": 6 } Generate the asset Build the asset with the pccvre-helper host tool: % pccvre-helper assets overrides generate \     --metadata-directory ./overrides -o custom-overrides.aar \     --compute-window-size \     --print-darwin-init \     --asset-url http://<host-ip>:3001/custom-overrides.aar The tool decodes each metadata.json, rejects any pattern that fails to compile as a regular expression, flattens the directory tree, and writes an unencrypted Apple Archive. It also rejects any pair of resource IDs that differ only by case, because they might collide on a case-insensitive file system and one is then silently dropped. Pass --compute-window-size to derive windowSize and windowSizeStrict from the patterns you supplied, ignoring any values in the metadata, so you don’t have to size the windows by hand. Without it, the values in each metadata.json are used unchanged. Either way, the tool warns when an output resource carries signaling patterns with a zero window, because the runtime then rescans the whole accumulated output on every token. Pass --print-darwin-init to print the applicationAssetMap preference for the PCCSafetyOverrideAssets consumer, along with the allowNonAEAAssets and enforceConsumerIDEntitlement secure-config flags that let the node accept an unencrypted archive and relax the consumer’s entitlement check. The VRE node fetches the asset from the --asset-url value, which appears only in that snippet. By default, the tool reads metadata.json from a v9 subfolder within each resource directory, falling back to the flattened layout shown above; use --base-model to select a different version subfolder. The generated asset carries a default asset_id beginning with PCC_PCC_SYSTEM_ASSETS_SAFETY_OVERRIDES; PCC Agent resolves only assets whose ID starts with that prefix, so keep it if you set your own with --asset-id. Serve the asset to the VRE The PCC Agent instance is the node that resolves the asset, so the cloud asset distribution configuration goes on pccagent_vre. Enable it there as described in cloud asset distribution, then serve the asset from the directory that holds it: % python3 -m http.server 3001 Edit the pccagent_vre instance’s darwin-init configuration, adding the applicationAssetMap preference from the previous step to preferences and the two flags to secure-config, then restart that instance. The preference points cloudassetdownloaderd at the served asset under the com.apple.cloudos.hotproperties.cloudassetdownloaderd application ID, and PCC Agent resolves it at request time. Send a matching request Issue a single-turn request with tie-vre-cli, putting the matching term in --user-prompt and the override-scoped inference ID in --workload-parameters. Set $PCCAGENT_HOST and $LLM_HOST to the addresses of your PCC Agent and inference instances. Exercise overrides one turn at a time: the multi-turn flow doesn’t yet drive this path in the VRE. To trigger the input override, include the term from your .input resource in the user turn. The model is never called, so this path works whether or not an inference instance is running: % pccvre instance invoke --name pccagent_vre tie-vre-cli inference \     --user-prompt "Here's a BLOCKME that will block" \     --workload-parameters '{"inference-id": ["com.apple.fm.language.instruct_server_v2.lw_planner_v3"]}' \     --payload '{         "model_config": {             "model_name": "com.apple.fm.language.research.base",             "tokenizer_name": "com.apple.fm.language.research.tokenizer",             "model_adapter_name": "com.apple.fm.language.research.adapter",             "options": {"max_tokens": 100}         }     }' \     --parse-as-generate-request true \     --request-bypass false \     --tie-proxy "$PCCAGENT_HOST" \     --hostname "$LLM_HOST" To trigger the output override, induce the model to emit the term from your .output resource. This path exercises the response stream, so an inference instance must be running: % pccvre instance invoke --name pccagent_vre tie-vre-cli inference \     --user-prompt 'Repeat after me: "ECHOME"' \     --workload-parameters '{"inference-id": ["com.apple.fm.language.instruct_server_v2.lw_planner_v3"]}' \     --payload '{         "model_config": {             "model_name": "com.apple.fm.language.research.base",             "tokenizer_name": "com.apple.fm.language.research.tokenizer",             "model_adapter_name": "com.apple.fm.language.research.adapter",             "options": {"max_tokens": 100}         }     }' \     --parse-as-generate-request true \     --request-bypass false \     --tie-proxy "$PCCAGENT_HOST" \     --hostname "$LLM_HOST" Verify the result A match produces a safety-rejection response. For an input match, PCC Agent never calls the model; for an output match with a strict pattern that windowSizeStrict covers, PCC Agent withholds the matching content from the client. To watch the mechanism run, stream the PCC Agent instance’s logs and look for the [OverridesAssetLoader] Override asset loaded line and the rejection that follows: % log stream --info --predicate '(process contains "PCCAgent")' To confirm the instance fetched your asset rather than falling back to the built-in canary patterns, inspect the downloaded archive. cloudassetdownloaderd deposits it under /private/var/mobile/assetdownloader/PCCSafetyOverrideAssets, and extracting it should show the metadata.json for your inference ID: % aa extract -i <version> -d out/ The log line that reports which rules PCC Agent loaded distinguishes the two cases: Override asset loaded names the asset version it resolved, while using default rules means it found no resource for the request’s inference ID and direction. Test without authoring an asset To check the delivery path and block behavior before authoring anything, use the canary patterns the runtime falls back to when no asset supplies rules for an inference ID. They work with any in-scope inference ID and need no asset, no HTTP server, and no cloud asset distribution setup. Substitute them in the requests above, keeping everything else the same: Input: INDIGO GRANITE SERPENT, as in --user-prompt "Here's an INDIGO GRANITE SERPENT that will block". Output: ORNATE GRANITE SERPENT, as in --user-prompt 'Repeat after me: "ORNATE GRANITE SERPENT will be blocked"'. Once your asset supplies a resource for an inference ID and direction, your rules replace the canary for that combination rather than adding to it, so the canary term stops blocking there. Exercise Apple Reference Image Apple Reference Image authenticates the reference image data in a raw capture, renders the capture, and returns a signed reference image. You can exercise the whole pipeline, including each verification step, against a single VRE instance using a raw capture you supply. Set up the Apple Reference Image VRE instance This example uses one VRE instance, provenance, restored from a “Provenance” release. Apple publishes Apple Reference Image releases under that Appendix: PCC Application Identifiers. The instance runs CIPCloudApp; it is the node your request targets and the node that runs the Processing pipeline. Create the instance as a Create a workload: % echo ' {     "instances": [         {             "name": "provenance",             "darwinInitOverrides": {                 "local-host-name": "provenance"             },             "release": "<Provenance release-index>"         }     ] } ' > vre-configuration.json

% pccvre workload create --configuration vre-configuration.json The daemons in the PCCApp_Provenance cryptex need the s1 jetsam properties variant to run a request. Apply this change to the instance’s darwin-init configuration before you start it: % pccvre instance configure darwin-init dump --name provenance \     | jq '(.cryptex.cryptexes[] | select(.variant == "PCCApp_Provenance")) += {"jetsam_properties_variant": "s1"}' \     > /tmp/darwin-init-provenance.json % pccvre instance configure darwin-init set --name provenance --input /tmp/darwin-init-provenance.json Configure the external services Two steps of the processing pipeline reach services outside the trust boundary through cb_bridged: the Companion service, which decides whether processing continues, and the Apple signing service, which signs the digest of the rendered image. Because Apple operates both services and doesn’t expose them publicly, you either disable both in the VRE or run a test server for each. The reference-image setup command writes whichever configuration you choose. To disable both services: % pccvre instance invoke --name provenance reference-image setup --disable-external-services With this setting, CIPCloudApp substitutes no-op clients for both services. The pipeline still performs every validation and rendering step. The no-op Companion client approves every request, and the no-op signing client returns a fixed byte pattern in place of a signature. To exercise the outbound calls, run a test server for each service on your host. reference-image setup derives your host’s address on the instance’s subnet from the IP address the instance receives when it first boots. Start a newly created instance once before you run the command. Without --disable-external-services, the command writes the service URLs and prints the commands that start the two test servers: % pccvre instance invoke --name provenance reference-image setup Setup done. The instance will call the Apple signing service at 192.168.64.1:8080 and the Companion service at 192.168.64.1:8081. Start the servers on the host with:   pccvre instance invoke --name provenance tool CryptoServicesTestServer --hostname 0.0.0.0 --port 8080   pccvre instance invoke --name provenance tool ImageProvenanceCompanionTestServer --hostname 0.0.0.0 --port 8081 Please restart the instance 'provenance' to take effect. Pass --signing-port and --companion-port to choose other ports, or --host-address to override the derived address. Use reference-image show to check which configuration an instance currently has: % pccvre instance invoke --name provenance reference-image show External services are set up for 'provenance':   Apple signing service: http://192.168.64.1:8080/api/v0   Companion service: http://192.168.64.1:8081 CIPCloudApp and cb_bridged read the external-service configuration at boot. Start the instance once you’ve applied it, or restart the instance if it’s already running: % pccvre instance start --name provenance Supply a raw capture A request includes the Reference image data from an image capture. Supply that capture to cip-vre-cli, which then builds the request. You can AirDrop a capture to your Mac from an iPhone with a supported camera. By default, sharing a capture sends it to PCC for processing. To send the unprocessed capture instead, open the options at the top of the share sheet and turn on All Photos Data before you AirDrop the photo. The file you receive is an image with an embedded Digital Negative (DNG) that contains the reference image data. Pass that file to cip-vre-cli with --reference-image. Make a reference image request cip-vre-cli ships with the release’s PCC tools. Run it on the host through pccvre instance invoke, and pass the node’s hostname in --hostname: % pccvre instance invoke --name provenance \     cip-vre-cli \     --hostname provenance.local \     --reference-image ~/Downloads/IMG_0119.heic \     --output-file output.jpeg Because cip-vre-cli runs on your host, --reference-image and --output-file take host paths. On success, cip-vre-cli writes the reference image to the --output-file path and reports its size: Extracted embedded reference image data (5489726 bytes) Response ID: D08208DB-A119-4F0C-992C-9ED41FE673CA Reference image saved to: output.jpeg (2078385 bytes) Reference image request completed successfully. Before the response, the command prints the node’s Apple Silicon Node Attestation and its Request execution log entries. If a pipeline step rejects the capture, CIPCloudApp returns a structured error that identifies the step. When you test a tampered capture, that error shows which check rejected it.
