Galileo Lemonade Instrumentation Setup
Prerequisites
| Tool or access |
Purpose |
Verify |
| Bash and Python 3 |
Run bundled setup and validation helpers |
bash --version && python3 --version |
| Required product/platform access |
Inspect or configure the selected target |
Complete the documented preflight |
| Credential files for live modes |
Keep secrets out of chat |
Verify paths only |
Workflow Overview
┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐
│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │
└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘
When to Activate
- Adding Galileo OTLP fan-out to a Lemonade collector, capturing agent/workflow/tool traces around Lemonade,
avoiding duplicate LLM records, or validating privacy-safe Galileo ingestion from an AMD Ryzen AI host.
- Preview and review the galileo lemonade instrumentation setup workflow before any live apply phase.
- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.
Scope
Follow the documented read-only or render-first path whenever it is available.
This skill does not imply permission to mutate live systems. Require explicit
apply flags, protected credentials, and operator review for state changes.
Examples
Inspect the supported setup modes before selecting one:
bash skills/galileo-lemonade-instrumentation-setup/scripts/setup.sh --help
Expected output: usage, supported modes, and required arguments are displayed
without changing the target environment.
Inspect validation modes before running completion checks:
bash skills/galileo-lemonade-instrumentation-setup/scripts/validate.sh --help
Expected output: offline, live, and completion options are displayed when the
skill supports them; help exits without mutation.
Troubleshooting
| Issue |
Cause |
Resolution |
| Preflight fails |
A required tool or access path is missing |
Resolve it before rendering or applying |
| Rendered assets are incomplete |
Required non-secret inputs are absent |
Complete intake and render again |
| Apply is blocked |
Review, credentials, or explicit acceptance is missing |
Use the documented handoff |
| Validation is incomplete |
Live evidence is unavailable |
Record the gap and keep completion open |
Purpose
Use this skill after $lemonade-splunk-otel has established a healthy,
privacy-safe Lemonade-to-Splunk trace path. It adds Galileo in one of two
explicit modes and proves delivery by backend readback.
The tested baseline is Lemonade v10.10 with Splunk OTel Collector v0.156;
Galileo SaaS and Enterprise still require an exact tenant intake endpoint.
Run the tools from an isolated Python environment containing
requirements-dev.txt (PyYAML 6.x). Rendering is safe offline; production
validation also requires the exact installed collector binary.
This skill does not treat Lemonade's native inference span as a complete AI
agent trace. Lemonade v10.10 creates one root SERVER span per request, does not
extract traceparent, and has no workflow/tool hierarchy.
Required Intake
Ask for and record the exact Galileo instance console URL. A copied console
link may include a navigation route after the host. Validate that exact link
with --galileo-console-url, but pass only its reported HTTPS origin to
$galileo-platform-setup. For example,
https://console.example.invalid/tenant-navigation normalizes to
https://console.example.invalid/ for endpoint derivation. Treat the
path as navigation context; never infer a project or Log stream from it.
The demo-v2 deployment used by the production example starts at
https://console.demo-v2.galileocloud.io/; still require and validate the
operator's full navigation URL instead of silently assuming that instance.
Resolve the API base, exact OTLP traces endpoint, project, and Log stream
independently. The renderer reports an endpoint candidate but keeps the
runtime value in GALILEO_OTLP_TRACES_ENDPOINT until tenant validation.
Choose One Galileo Source
| Requirement |
Mode |
Galileo receives |
Privacy consequence |
| No application change; model/latency/token metadata |
server-fanout |
Lemonade's native LLM root spans |
With Lemonade hide flags on, input/output/thinking stay [REDACTED]; content evaluators are limited. |
| Agent, workflow, tool, session, async, or selective evaluation context |
client-fanout |
Caller-side OpenInference/OTel spans, Galileo-only by default |
Recommended for actual agent observability. Native Lemonade remains redacted and Splunk-only. |
| Remove Galileo routing without disturbing Splunk |
splunk-only |
Nothing |
Rollback/render cleanup mode. |
Do not send both native and caller-instrumented LLM spans to the same Galileo
Log stream. They have unrelated trace IDs and appear as duplicate observations.
If temporary comparison is required, use separate Log streams and label it.
Direct Lemonade-to-Galileo is technically possible but is not the default: the
server has one OTLP destination, so it displaces Splunk and exposes the
Galileo key to the Lemonade service.
Safety Contract
- Validate the exact Galileo console URL, normalize a copied navigation link
to its origin, and do not assume public Galileo Cloud.
- Use
$galileo-platform-setup for tenant readiness and project/Log stream
lifecycle. Prefer immutable project and Log stream IDs after discovery.
- Require the exact tenant-supported
traces_endpoint. Current Galileo docs
show both /otel/v1/traces for raw OTLP POST and /otel/traces for several
exporter/SDK integrations. Do not derive one from the client type or let the
collector append a path.
- Stock Collector v0.156 follows HTTP redirects and can copy custom headers to
the redirect target. Pin the endpoint to a separately discovered
GALILEO_EXPECTED_ORIGIN, then route only otlp_http/galileo_lemonade
through the literal Collector v0.156 proxy_url field. The proxy must be a
dedicated loopback tinyproxy with FilterDefaultDeny Yes; its only filter
rule is the anchored, regex-escaped exact host derived from that pinned
origin. Production revalidates protected binary/config/filter path identity,
inode, metadata, and SHA-256, then runs bounded credential-free CONNECT
probes that require HTTP 403 for an unlisted host and 2xx for the exact
Galileo host. All Splunk exporters remain direct. Ambient proxy variables
are stripped and are never part of this contract. Install evidence as
root-owned, collector-group-readable mode 0440; a root 0400 file cannot
be read by the non-root collector wrapper.
- Use the current collector component type
otlp_http, not legacy
otlphttp. This skill names its instance otlp_http/galileo_lemonade so it
cannot overwrite another application's Galileo exporter.
- Keep Galileo credentials in a dedicated service-user-owned
0600 file
(root-owned only when the collector runs as root).
Generated YAML contains only ${env:...} placeholders.
- Use
scripts/galileo_bootstrap_transaction.py when a broad bootstrap key
must create or adopt the exact target and mint the project-scoped runtime
key. The bootstrap secret is accepted only from a current-user-owned,
single-link protected file; it is never accepted through argv or the
environment. Keep the private journal and one-time runtime-key output until
the transaction is finalized or rolled back.
- Bootstrap stops at
RUNTIME_KEY_CREATED. Never revoke the old key in that
invocation. Record fresh, exact cutover evidence and run the separate
finalize command with a distinct reviewed unscoped revoker credential only
after host cutover, Galileo API trace/hierarchy and
privacy readback, and unchanged Splunk backend readback all pass. Console UI
review is not inferred from API evidence and is not a revocation gate.
- Use
GALILEO_API_KEY_FILE with the packaged collector runtime wrapper. Do
not source a plaintext key into an interactive shell or store it in the
non-secret collector environment file.
- Pin the collector the wrapper may exec with
GALILEO_COLLECTOR_BINARY and
GALILEO_COLLECTOR_BINARY_SHA256. Exec mode requires both and fails closed
without them, before the API key is read. Exec mode also requires Linux and
refuses to run elsewhere, because the binary and every ancestor directory
must be proven root-owned, link-free, and not group/other-writable.
Recompute the digest after every collector package change.
- Render one complete config from the live base, review its diff, validate with
the exact installed collector binary, back up, then apply transactionally.
- Keep both Lemonade and client OTLP receivers loopback-bound.
- Treat
service.name filtering as classification, not authentication. Use
server-fanout only within a loopback/single-host trust boundary and accept
its shared-receiver replay risk explicitly during production validation.
- Use the persistent Galileo queue for production. The memory queue is an
accepted-loss development option and cannot pass
--production validation.
- Bind every persistent queue to the SHA-256 of its validated endpoint and
selector pair. The queue directory's final component must be that fingerprint;
never reuse, rename, or copy it to a different destination.
- Delete every
galileo.* resource, span, and event attribute immediately
before the Galileo exporter so in-band project, Log stream, experiment, or
dataset fields cannot override the fixed exporter headers.
- Never disable content hiding without explicit approval of every backend that
will receive the affected pipeline.
Workflow
Read reference.md, then load the architecture, application,
or validation reference required by the chosen mode.
Run $lemonade-splunk-otel discovery and confirm the existing Splunk path,
privacy flags, native trace pipeline name, collector config, and receiver.
Run $galileo-platform-setup readiness for the user-confirmed instance.
Put the existing bootstrap key in a protected file without printing it and
identify its exact API-key ID. For read-only inventory, resolve immutable
project and Log stream IDs without creating objects:
python3 skills/galileo-lemonade-instrumentation-setup/scripts/galileo_target_discovery.py \
--api-base "$GALILEO_API_BASE" \
--api-key-file "$GALILEO_API_KEY_FILE" \
--api-key-header Splunk-AO-API-Key
Filter with exact --project-name or --project-id when the tenant has
many projects. Current v2 project/read APIs document
Splunk-AO-API-Key; OTLP ingest separately uses Galileo-API-Key.
Confirm the selected Log stream before rendering.
When the target or project-scoped runtime key must be created, use the
phased bootstrap transaction in
references/runtime-credentials.md.
Existing targets require explicit adoption, preferably by exact IDs. The
default candidate role is annotator; it is accepted only if a live API
probe proves exact project-only visibility and log_data. If that probe
fails, roll back the exact owned key and start a new transaction before
trying editor; do not claim either role is least privilege without the
live permission proof.
State the selected Galileo source and content policy before rendering.
With the confirmed endpoint, expected origin, and exactly one selector pair
set in the protected runtime environment, calculate the non-secret
destination fingerprint. This command emits only the lowercase digest and
does not require or print the API key:
python3 skills/galileo-lemonade-instrumentation-setup/scripts/collector_runtime_wrapper.py \
--print-destination-fingerprint
Record it as GALILEO_DESTINATION_FINGERPRINT, and set
GALILEO_QUEUE_STORAGE_DIRECTORY to a new private directory ending with
that exact digest.
Pin the collector the wrapper may exec. Record the reviewed binary as
GALILEO_COLLECTOR_BINARY and its digest as
GALILEO_COLLECTOR_BINARY_SHA256, read from the installed file itself, not
from a vendor download page:
sha256sum /usr/bin/otelcol
Render from the existing full collector config:
bash skills/galileo-lemonade-instrumentation-setup/scripts/setup.sh \
--galileo-console-url "$GALILEO_CONSOLE_URL" \
--base /etc/otel/collector/agent_config.yaml \
--output /tmp/lemonade-galileo-agent_config.yaml \
--mode client-fanout \
--routing ids \
--galileo-proxy-url http://127.0.0.1:18888 \
--queue-policy persistent \
--production \
--destination-fingerprint "$GALILEO_DESTINATION_FINGERPRINT" \
--queue-storage-directory "$GALILEO_QUEUE_STORAGE_DIRECTORY"
Review the diff, then apply four independently journaled layers in dependency
order: create the destination-fingerprinted directory with
transactional_queue_directory.py; install and probe the dedicated
tinyproxy package/config/filter/unit with transactional_proxy_bundle.py;
render protected proxy identity evidence from those installed assets; and
install the routing environment, evidence, wrapper, key, and drop-in with
transactional_runtime_bundle.py. Follow
references/queue-directory-transaction.md,
references/proxy-bundle-transaction.md,
references/runtime-bundle-transaction.md,
after reading the underlying credential contract in
references/runtime-credentials.md.
Do not apply the collector YAML yet. Start the proxy and run the wrapper's
--check; it must prove the protected assets plus credential-free live
allow/deny probes. Then validate the staged YAML statically and with the
installed collector:
Use $lemonade-splunk-otel's value-free config_change_summary.py first;
PyYAML normalizes formatting and comments, so retain the exact source backup.
The production validator inspects service-owned queue files and
collector-group-readable proxy evidence. Run the command under the exact
Collector UID, primary GID, and supplementary groups, while inheriting the
protected systemd environment without copying secret values into argv. Do
not run it as root: root's group set is not proof that the Collector can
read or safely own those assets.
# Execute as the discovered Collector service identity, not as root.
bash skills/galileo-lemonade-instrumentation-setup/scripts/validate.sh \
--collector-config /tmp/lemonade-galileo-agent_config.yaml \
--mode client-fanout \
--queue-policy persistent \
--production \
--galileo-proxy-url http://127.0.0.1:18888 \
--destination-fingerprint "$GALILEO_DESTINATION_FINGERPRINT" \
--queue-storage-directory "$GALILEO_QUEUE_STORAGE_DIRECTORY" \
--collector-binary /usr/bin/otelcol
Back up the live collector config and service state, preserving the exact
original command/arguments. After the three prerequisite transactions and
service-identity validation pass, use the baseline skill's SHA-gated
transactional apply helper for the validated YAML and restart,
with /etc/splunk-otel-collector/lemonade-agent-config.yaml as the live
config path pinned by the runtime manifest.
The wrapper validates endpoint/origin, selectors, destination fingerprint,
proxy assets/live probes, and queue before loading the protected key only in
the collector child. Restore the collector YAML transaction immediately if
Splunk regresses, then restore the exact Collector YAML manifest, runtime
manifest, proxy manifest, and queue manifest in that reverse order. Queue
restore is last and quarantines nonempty or uncertain data; do not roll back
only one proxy/runtime file or delete a queue database manually.
For client-fanout, adapt
skills/galileo-lemonade-instrumentation-setup/assets/lemonade_openinference_client.py.
It sends to the dedicated
loopback receiver and keeps Galileo credentials out of the application.
Install its pinned requirements in an isolated environment, then run
lemonade_openinference_client.py --check under the application identity
before sending the real canary.
Send the synthetic canary through the receiver selected by the mode. A
receiver success is only pipeline evidence; continue to Galileo readback.
Follow references/validation.md, including a
real non-sensitive Lemonade request, collector counter deltas, Galileo API
trace/hierarchy readback, privacy assertions, and unchanged Splunk backend
readback. Perform Console trace-shape review only when a signed-in browser
is actually available, and report its absence truthfully.
Build a fresh schema-v2 cutover document from the actual host, Galileo API,
and Splunk backend results. Record it with the transaction's
record-cutover-evidence command. Omit console_review or record only
{"status":"not_observed"}; any signed-in UI review is separate evidence.
In a distinct invocation, run finalize with the same protected bootstrap
file plus a distinct protected unscoped revoker file and its exact key ID.
It revalidates the evidence and runtime key, verifies that the revoker is
neither the old nor runtime key, revokes only the bound old key ID through
that revoker, reconciles full-inventory absence, requires the old key to
return 401 Unauthorized from both /v2/current_user and /v2/token,
rechecks the runtime key, and reaches FINALIZED. Before revocation,
rollback deletes only exact transaction-owned IDs and preserves adopted
targets. The separately documented reconcile-legacy-revocation command
is only for the exact retired, already-started self-delete journal schema;
it performs no DELETE and must never replace the fresh revoker policy.
Rendered Collector Shapes
server-fanout leaves the shared native traces pipeline's exporters
unchanged and adds traces/lemonade_galileo_server. The new branch shares the
reviewed receiver set but fail-closed filters on Lemonade's native
service.name=lemonade-server before the Galileo-only exporter and preserves
the baseline Lemonade deployment/privacy transform. The attribute filter does
not establish provenance; production validation rejects externally bound
receivers.
client-fanout keeps the native traces pipeline Splunk-only and creates:
OpenAI-compatible caller
-> 127.0.0.1:14318/v1/traces
-> traces/lemonade_galileo_client
-> otlp_http/galileo_lemonade
This default avoids duplicate LLM/cost records in both backends and permits a
caller-specific Galileo content policy. --mirror-client-to-native-exporters
is an explicit exception for users who want the richer caller hierarchy in
Splunk too; it requires --allow-client-mirror during validation and an
approved duplicate/content-handling plan.
The renderer inherits only baseline memory_limiter, resource_detection
(or resourcedetection when that is the live distro ID), and batch
processor types. Use repeated --client-processor only after reviewing
the component for source-specific filters, transforms, and content expansion;
validation then requires --allow-custom-client-processors.
Every custom processor must precede the managed client privacy transform. The
privacy transform and Galileo route guard are the final two non-batch
processors, followed only by a terminal batch suffix or direct export;
rendering and validation fail if any processor could mutate spans after them.
The managed resource processor runs after inherited resource detection and
upserts the dedicated client service.name; validation rejects an insert
action that could retain the host application's identity.
Both modes redact error status text; client mode also deletes known
content-bearing span/event attributes—including multimodal message payloads and
message-level function/tool arguments and results—while retaining roles,
models, providers, structural IDs, and content types. It deletes user.id and
arbitrary tags/metadata, but retains opaque session.id for session grouping;
never put personal data in that ID. It also redacts exception messages and
stack traces. Agent/Tool input.value, output.value, and tool call
arguments/results are restored only as the constant [REDACTED] after deletion
so required hierarchy fields remain without source content. Source-side
OpenInference hiding remains mandatory as defense in depth, with GenAI semantic
convention duplication explicitly disabled in the reference client.
Lemonade v10.10's native hide_outputs does not
cover status.message, so removing these transforms can expose an error that
echoes sensitive content.
The renderer strips only an exact recognized prior render before adding the
requested mode, so repeated renders and mode switches are deterministic. It
preserves unrelated components but fails closed on managed drift, foreign
references, every custom Galileo-shaped or Galileo-named exporter/route in all
modes, and any extra pipeline sharing the dedicated client receiver.
Application Choices
- OpenInference + standard OpenAI instrumentation: preferred for sync/async,
streaming, OTel context propagation, collector fan-out, and strong hide
controls. The packaged client demonstrates this path.
- Galileo OpenAI wrapper: smallest synchronous change and supports
OpenAI-compatible model servers, but captures raw input/output by default.
- Galileo OpenAI Agents tracing processor: best when the application actually
uses OpenAI Agents and needs generations, tools, and handoffs.
- Galileo manual logger or
@log: use for custom agent/framework semantics or
explicit redacted fields.
Read references/application-instrumentation.md
before choosing a client library. Content capture is opt-in.
Completion Gate
Report all of the following:
- chosen mode and why the other source is excluded;
- exact Galileo instance/API endpoint and project/Log stream IDs, with secrets
omitted;
- Lemonade version, health, semantics, and privacy flags;
- collector config validation, loopback binds, service health, exact
accepted/failed/refused and sent/send-failed/enqueue-failed deltas,
queue/in-flight state, and unchanged Splunk readback;
- Galileo API readback proving the expected trace, Agent/Tool/LLM hierarchy,
and privacy state. Report signed-in Console confirmation separately when it
was actually observed; otherwise report it as not observed;
- bootstrap transaction phase and sanitized IDs, with
FINALIZED required
only after the separate fresh-evidence revocation gate;
- backup and tested rollback path.
Production completion still requires live Galileo backend readback of the
Agent/Tool/LLM hierarchy. Static validation, collector acceptance, and an empty
or healthy queue do not substitute for that deployment gate.
HTTP 200 alone is insufficient: OTLP responses can contain
partialSuccess.rejectedSpans, and collector counters do not prove backend
storage.
1---2name: galileo-lemonade-instrumentation-setup3description: Use when adding Galileo OTLP fan-out to a Lemonade collector, capturing agent/workflow/tool traces around Lemonade, avoiding duplicate LLM records, or validating privacy-safe Galileo ingestion from an AMD Ryzen AI host. Instrument Lemonade Server inference and OpenAI-compatible calling applications for Galileo Observe while preserving Splunk OpenTelemetry delivery, privacy policy, rollback, and end-to-end readback.4---56# Galileo Lemonade Instrumentation Setup78## Prerequisites910| Tool or access | Purpose | Verify |11|---|---|---|12| Bash and Python 3 | Run bundled setup and validation helpers | `bash --version && python3 --version` |13| Required product/platform access | Inspect or configure the selected target | Complete the documented preflight |14| Credential files for live modes | Keep secrets out of chat | Verify paths only |1516## Workflow Overview1718```text19┌───────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐20│ Preflight │ → │ Render/review │ → │ Apply/handoff │ → │ Validate evidence │21└───────────┘ └───────────────┘ └───────────────┘ └─────────────────┘22```2324## When to Activate2526- Adding Galileo OTLP fan-out to a Lemonade collector, capturing agent/workflow/tool traces around Lemonade,27 avoiding duplicate LLM records, or validating privacy-safe Galileo ingestion from an AMD Ryzen AI host.28- Preview and review the galileo lemonade instrumentation setup workflow before any live apply phase.29- Diagnose failed prerequisites, generated assets, configuration, or validation evidence.3031## Scope3233Follow the documented read-only or render-first path whenever it is available.34This skill does not imply permission to mutate live systems. Require explicit35apply flags, protected credentials, and operator review for state changes.3637## Examples3839Inspect the supported setup modes before selecting one:4041```bash42bash skills/galileo-lemonade-instrumentation-setup/scripts/setup.sh --help43```4445Expected output: usage, supported modes, and required arguments are displayed46without changing the target environment.4748Inspect validation modes before running completion checks:4950```bash51bash skills/galileo-lemonade-instrumentation-setup/scripts/validate.sh --help52```5354Expected output: offline, live, and completion options are displayed when the55skill supports them; help exits without mutation.5657## Troubleshooting5859| Issue | Cause | Resolution |60|---|---|---|61| Preflight fails | A required tool or access path is missing | Resolve it before rendering or applying |62| Rendered assets are incomplete | Required non-secret inputs are absent | Complete intake and render again |63| Apply is blocked | Review, credentials, or explicit acceptance is missing | Use the documented handoff |64| Validation is incomplete | Live evidence is unavailable | Record the gap and keep completion open |6566## Purpose6768Use this skill after `$lemonade-splunk-otel` has established a healthy,69privacy-safe Lemonade-to-Splunk trace path. It adds Galileo in one of two70explicit modes and proves delivery by backend readback.7172The tested baseline is Lemonade v10.10 with Splunk OTel Collector v0.156;73Galileo SaaS and Enterprise still require an exact tenant intake endpoint.74Run the tools from an isolated Python environment containing75`requirements-dev.txt` (PyYAML 6.x). Rendering is safe offline; production76validation also requires the exact installed collector binary.7778This skill does **not** treat Lemonade's native inference span as a complete AI79agent trace. Lemonade v10.10 creates one root SERVER span per request, does not80extract `traceparent`, and has no workflow/tool hierarchy.8182## Required Intake8384Ask for and record the exact Galileo instance console URL. A copied console85link may include a navigation route after the host. Validate that exact link86with `--galileo-console-url`, but pass only its reported HTTPS origin to87`$galileo-platform-setup`. For example,88`https://console.example.invalid/tenant-navigation` normalizes to89`https://console.example.invalid/` for endpoint derivation. Treat the90path as navigation context; never infer a project or Log stream from it.91The demo-v2 deployment used by the production example starts at92`https://console.demo-v2.galileocloud.io/`; still require and validate the93operator's full navigation URL instead of silently assuming that instance.9495Resolve the API base, exact OTLP traces endpoint, project, and Log stream96independently. The renderer reports an endpoint candidate but keeps the97runtime value in `GALILEO_OTLP_TRACES_ENDPOINT` until tenant validation.9899## Choose One Galileo Source100101| Requirement | Mode | Galileo receives | Privacy consequence |102|---|---|---|---|103| No application change; model/latency/token metadata | `server-fanout` | Lemonade's native LLM root spans | With Lemonade hide flags on, input/output/thinking stay `[REDACTED]`; content evaluators are limited. |104| Agent, workflow, tool, session, async, or selective evaluation context | `client-fanout` | Caller-side OpenInference/OTel spans, Galileo-only by default | Recommended for actual agent observability. Native Lemonade remains redacted and Splunk-only. |105| Remove Galileo routing without disturbing Splunk | `splunk-only` | Nothing | Rollback/render cleanup mode. |106107Do not send both native and caller-instrumented LLM spans to the same Galileo108Log stream. They have unrelated trace IDs and appear as duplicate observations.109If temporary comparison is required, use separate Log streams and label it.110111Direct Lemonade-to-Galileo is technically possible but is not the default: the112server has one OTLP destination, so it displaces Splunk and exposes the113Galileo key to the Lemonade service.114115## Safety Contract116117- Validate the exact Galileo console URL, normalize a copied navigation link118 to its origin, and do not assume public Galileo Cloud.119- Use `$galileo-platform-setup` for tenant readiness and project/Log stream120 lifecycle. Prefer immutable project and Log stream IDs after discovery.121- Require the exact tenant-supported `traces_endpoint`. Current Galileo docs122 show both `/otel/v1/traces` for raw OTLP POST and `/otel/traces` for several123 exporter/SDK integrations. Do not derive one from the client type or let the124 collector append a path.125- Stock Collector v0.156 follows HTTP redirects and can copy custom headers to126 the redirect target. Pin the endpoint to a separately discovered127 `GALILEO_EXPECTED_ORIGIN`, then route only `otlp_http/galileo_lemonade`128 through the literal Collector v0.156 `proxy_url` field. The proxy must be a129 dedicated loopback tinyproxy with `FilterDefaultDeny Yes`; its only filter130 rule is the anchored, regex-escaped exact host derived from that pinned131 origin. Production revalidates protected binary/config/filter path identity,132 inode, metadata, and SHA-256, then runs bounded credential-free CONNECT133 probes that require HTTP 403 for an unlisted host and 2xx for the exact134 Galileo host. All Splunk exporters remain direct. Ambient proxy variables135 are stripped and are never part of this contract. Install evidence as136 root-owned, collector-group-readable mode `0440`; a root `0400` file cannot137 be read by the non-root collector wrapper.138- Use the current collector component type `otlp_http`, not legacy139 `otlphttp`. This skill names its instance `otlp_http/galileo_lemonade` so it140 cannot overwrite another application's Galileo exporter.141- Keep Galileo credentials in a dedicated service-user-owned `0600` file142 (root-owned only when the collector runs as root).143 Generated YAML contains only `${env:...}` placeholders.144- Use `scripts/galileo_bootstrap_transaction.py` when a broad bootstrap key145 must create or adopt the exact target and mint the project-scoped runtime146 key. The bootstrap secret is accepted only from a current-user-owned,147 single-link protected file; it is never accepted through argv or the148 environment. Keep the private journal and one-time runtime-key output until149 the transaction is finalized or rolled back.150- Bootstrap stops at `RUNTIME_KEY_CREATED`. Never revoke the old key in that151 invocation. Record fresh, exact cutover evidence and run the separate152 `finalize` command with a distinct reviewed unscoped revoker credential only153 after host cutover, Galileo API trace/hierarchy and154 privacy readback, and unchanged Splunk backend readback all pass. Console UI155 review is not inferred from API evidence and is not a revocation gate.156- Use `GALILEO_API_KEY_FILE` with the packaged collector runtime wrapper. Do157 not source a plaintext key into an interactive shell or store it in the158 non-secret collector environment file.159- Pin the collector the wrapper may exec with `GALILEO_COLLECTOR_BINARY` and160 `GALILEO_COLLECTOR_BINARY_SHA256`. Exec mode requires both and fails closed161 without them, before the API key is read. Exec mode also requires Linux and162 refuses to run elsewhere, because the binary and every ancestor directory163 must be proven root-owned, link-free, and not group/other-writable.164 Recompute the digest after every collector package change.165- Render one complete config from the live base, review its diff, validate with166 the exact installed collector binary, back up, then apply transactionally.167- Keep both Lemonade and client OTLP receivers loopback-bound.168- Treat `service.name` filtering as classification, not authentication. Use169 `server-fanout` only within a loopback/single-host trust boundary and accept170 its shared-receiver replay risk explicitly during production validation.171- Use the persistent Galileo queue for production. The memory queue is an172 accepted-loss development option and cannot pass `--production` validation.173- Bind every persistent queue to the SHA-256 of its validated endpoint and174 selector pair. The queue directory's final component must be that fingerprint;175 never reuse, rename, or copy it to a different destination.176- Delete every `galileo.*` resource, span, and event attribute immediately177 before the Galileo exporter so in-band project, Log stream, experiment, or178 dataset fields cannot override the fixed exporter headers.179- Never disable content hiding without explicit approval of every backend that180 will receive the affected pipeline.181182## Workflow1831841. Read [reference.md](reference.md), then load the architecture, application,185 or validation reference required by the chosen mode.1862. Run `$lemonade-splunk-otel` discovery and confirm the existing Splunk path,187 privacy flags, native trace pipeline name, collector config, and receiver.1883. Run `$galileo-platform-setup` readiness for the user-confirmed instance.189 Put the existing bootstrap key in a protected file without printing it and190 identify its exact API-key ID. For read-only inventory, resolve immutable191 project and Log stream IDs without creating objects:192193 ```bash194 python3 skills/galileo-lemonade-instrumentation-setup/scripts/galileo_target_discovery.py \195 --api-base "$GALILEO_API_BASE" \196 --api-key-file "$GALILEO_API_KEY_FILE" \197 --api-key-header Splunk-AO-API-Key198 ```199200 Filter with exact `--project-name` or `--project-id` when the tenant has201 many projects. Current v2 project/read APIs document202 `Splunk-AO-API-Key`; OTLP ingest separately uses `Galileo-API-Key`.203 Confirm the selected Log stream before rendering.204205 When the target or project-scoped runtime key must be created, use the206 phased bootstrap transaction in207 [references/runtime-credentials.md](references/runtime-credentials.md).208 Existing targets require explicit adoption, preferably by exact IDs. The209 default candidate role is `annotator`; it is accepted only if a live API210 probe proves exact project-only visibility and `log_data`. If that probe211 fails, roll back the exact owned key and start a new transaction before212 trying `editor`; do not claim either role is least privilege without the213 live permission proof.2144. State the selected Galileo source and content policy before rendering.2155. With the confirmed endpoint, expected origin, and exactly one selector pair216 set in the protected runtime environment, calculate the non-secret217 destination fingerprint. This command emits only the lowercase digest and218 does not require or print the API key:219220 ```bash221 python3 skills/galileo-lemonade-instrumentation-setup/scripts/collector_runtime_wrapper.py \222 --print-destination-fingerprint223 ```224225 Record it as `GALILEO_DESTINATION_FINGERPRINT`, and set226 `GALILEO_QUEUE_STORAGE_DIRECTORY` to a new private directory ending with227 that exact digest.228229 Pin the collector the wrapper may exec. Record the reviewed binary as230 `GALILEO_COLLECTOR_BINARY` and its digest as231 `GALILEO_COLLECTOR_BINARY_SHA256`, read from the installed file itself, not232 from a vendor download page:233234 ```bash235 sha256sum /usr/bin/otelcol236 ```237238 Render from the existing full collector config:239240 ```bash241 bash skills/galileo-lemonade-instrumentation-setup/scripts/setup.sh \242 --galileo-console-url "$GALILEO_CONSOLE_URL" \243 --base /etc/otel/collector/agent_config.yaml \244 --output /tmp/lemonade-galileo-agent_config.yaml \245 --mode client-fanout \246 --routing ids \247 --galileo-proxy-url http://127.0.0.1:18888 \248 --queue-policy persistent \249 --production \250 --destination-fingerprint "$GALILEO_DESTINATION_FINGERPRINT" \251 --queue-storage-directory "$GALILEO_QUEUE_STORAGE_DIRECTORY"252 ```2532546. Review the diff, then apply four independently journaled layers in dependency255 order: create the destination-fingerprinted directory with256 `transactional_queue_directory.py`; install and probe the dedicated257 tinyproxy package/config/filter/unit with `transactional_proxy_bundle.py`;258 render protected proxy identity evidence from those installed assets; and259 install the routing environment, evidence, wrapper, key, and drop-in with260 `transactional_runtime_bundle.py`. Follow261 [references/queue-directory-transaction.md](references/queue-directory-transaction.md),262 [references/proxy-bundle-transaction.md](references/proxy-bundle-transaction.md),263 [references/runtime-bundle-transaction.md](references/runtime-bundle-transaction.md),264 after reading the underlying credential contract in265 [references/runtime-credentials.md](references/runtime-credentials.md).266 Do not apply the collector YAML yet. Start the proxy and run the wrapper's267 `--check`; it must prove the protected assets plus credential-free live268 allow/deny probes. Then validate the staged YAML statically and with the269 installed collector:270271 Use `$lemonade-splunk-otel`'s value-free `config_change_summary.py` first;272 PyYAML normalizes formatting and comments, so retain the exact source backup.273274 The production validator inspects service-owned queue files and275 collector-group-readable proxy evidence. Run the command under the exact276 Collector UID, primary GID, and supplementary groups, while inheriting the277 protected systemd environment without copying secret values into argv. Do278 not run it as root: root's group set is not proof that the Collector can279 read or safely own those assets.280281 ```bash282 # Execute as the discovered Collector service identity, not as root.283 bash skills/galileo-lemonade-instrumentation-setup/scripts/validate.sh \284 --collector-config /tmp/lemonade-galileo-agent_config.yaml \285 --mode client-fanout \286 --queue-policy persistent \287 --production \288 --galileo-proxy-url http://127.0.0.1:18888 \289 --destination-fingerprint "$GALILEO_DESTINATION_FINGERPRINT" \290 --queue-storage-directory "$GALILEO_QUEUE_STORAGE_DIRECTORY" \291 --collector-binary /usr/bin/otelcol292 ```2932947. Back up the live collector config and service state, preserving the exact295 original command/arguments. After the three prerequisite transactions and296 service-identity validation pass, use the baseline skill's SHA-gated297 transactional apply helper for the validated YAML and restart,298 with `/etc/splunk-otel-collector/lemonade-agent-config.yaml` as the live299 config path pinned by the runtime manifest.300 The wrapper validates endpoint/origin, selectors, destination fingerprint,301 proxy assets/live probes, and queue before loading the protected key only in302 the collector child. Restore the collector YAML transaction immediately if303 Splunk regresses, then restore the exact Collector YAML manifest, runtime304 manifest, proxy manifest, and queue manifest in that reverse order. Queue305 restore is last and quarantines nonempty or uncertain data; do not roll back306 only one proxy/runtime file or delete a queue database manually.3078. For `client-fanout`, adapt308 `skills/galileo-lemonade-instrumentation-setup/assets/lemonade_openinference_client.py`.309 It sends to the dedicated310 loopback receiver and keeps Galileo credentials out of the application.311 Install its pinned requirements in an isolated environment, then run312 `lemonade_openinference_client.py --check` under the application identity313 before sending the real canary.3149. Send the synthetic canary through the receiver selected by the mode. A315 receiver success is only pipeline evidence; continue to Galileo readback.31610. Follow [references/validation.md](references/validation.md), including a317 real non-sensitive Lemonade request, collector counter deltas, Galileo API318 trace/hierarchy readback, privacy assertions, and unchanged Splunk backend319 readback. Perform Console trace-shape review only when a signed-in browser320 is actually available, and report its absence truthfully.32111. Build a fresh schema-v2 cutover document from the actual host, Galileo API,322 and Splunk backend results. Record it with the transaction's323 `record-cutover-evidence` command. Omit `console_review` or record only324 `{"status":"not_observed"}`; any signed-in UI review is separate evidence.32512. In a distinct invocation, run `finalize` with the same protected bootstrap326 file plus a distinct protected unscoped revoker file and its exact key ID.327 It revalidates the evidence and runtime key, verifies that the revoker is328 neither the old nor runtime key, revokes only the bound old key ID through329 that revoker, reconciles full-inventory absence, requires the old key to330 return 401 Unauthorized from both `/v2/current_user` and `/v2/token`,331 rechecks the runtime key, and reaches `FINALIZED`. Before revocation,332 `rollback` deletes only exact transaction-owned IDs and preserves adopted333 targets. The separately documented `reconcile-legacy-revocation` command334 is only for the exact retired, already-started self-delete journal schema;335 it performs no DELETE and must never replace the fresh revoker policy.336337## Rendered Collector Shapes338339`server-fanout` leaves the shared native `traces` pipeline's exporters340unchanged and adds `traces/lemonade_galileo_server`. The new branch shares the341reviewed receiver set but fail-closed filters on Lemonade's native342`service.name=lemonade-server` before the Galileo-only exporter and preserves343the baseline Lemonade deployment/privacy transform. The attribute filter does344not establish provenance; production validation rejects externally bound345receivers.346347`client-fanout` keeps the native `traces` pipeline Splunk-only and creates:348349```text350OpenAI-compatible caller351 -> 127.0.0.1:14318/v1/traces352 -> traces/lemonade_galileo_client353 -> otlp_http/galileo_lemonade354```355356This default avoids duplicate LLM/cost records in both backends and permits a357caller-specific Galileo content policy. `--mirror-client-to-native-exporters`358is an explicit exception for users who want the richer caller hierarchy in359Splunk too; it requires `--allow-client-mirror` during validation and an360approved duplicate/content-handling plan.361362The renderer inherits only baseline `memory_limiter`, `resource_detection`363(or `resourcedetection` when that is the live distro ID), and `batch`364processor types. Use repeated `--client-processor` only after reviewing365the component for source-specific filters, transforms, and content expansion;366validation then requires `--allow-custom-client-processors`.367Every custom processor must precede the managed client privacy transform. The368privacy transform and Galileo route guard are the final two non-batch369processors, followed only by a terminal batch suffix or direct export;370rendering and validation fail if any processor could mutate spans after them.371The managed resource processor runs after inherited resource detection and372upserts the dedicated client `service.name`; validation rejects an `insert`373action that could retain the host application's identity.374375Both modes redact error status text; client mode also deletes known376content-bearing span/event attributes—including multimodal message payloads and377message-level function/tool arguments and results—while retaining roles,378models, providers, structural IDs, and content types. It deletes `user.id` and379arbitrary tags/metadata, but retains opaque `session.id` for session grouping;380never put personal data in that ID. It also redacts exception messages and381stack traces. Agent/Tool `input.value`, `output.value`, and tool call382arguments/results are restored only as the constant `[REDACTED]` after deletion383so required hierarchy fields remain without source content. Source-side384OpenInference hiding remains mandatory as defense in depth, with GenAI semantic385convention duplication explicitly disabled in the reference client.386Lemonade v10.10's native `hide_outputs` does not387cover `status.message`, so removing these transforms can expose an error that388echoes sensitive content.389390The renderer strips only an exact recognized prior render before adding the391requested mode, so repeated renders and mode switches are deterministic. It392preserves unrelated components but fails closed on managed drift, foreign393references, every custom Galileo-shaped or Galileo-named exporter/route in all394modes, and any extra pipeline sharing the dedicated client receiver.395396## Application Choices397398- OpenInference + standard OpenAI instrumentation: preferred for sync/async,399 streaming, OTel context propagation, collector fan-out, and strong hide400 controls. The packaged client demonstrates this path.401- Galileo OpenAI wrapper: smallest synchronous change and supports402 OpenAI-compatible model servers, but captures raw input/output by default.403- Galileo OpenAI Agents tracing processor: best when the application actually404 uses OpenAI Agents and needs generations, tools, and handoffs.405- Galileo manual logger or `@log`: use for custom agent/framework semantics or406 explicit redacted fields.407408Read [references/application-instrumentation.md](references/application-instrumentation.md)409before choosing a client library. Content capture is opt-in.410411## Completion Gate412413Report all of the following:414415- chosen mode and why the other source is excluded;416- exact Galileo instance/API endpoint and project/Log stream IDs, with secrets417 omitted;418- Lemonade version, health, semantics, and privacy flags;419- collector config validation, loopback binds, service health, exact420 accepted/failed/refused and sent/send-failed/enqueue-failed deltas,421 queue/in-flight state, and unchanged Splunk readback;422- Galileo API readback proving the expected trace, Agent/Tool/LLM hierarchy,423 and privacy state. Report signed-in Console confirmation separately when it424 was actually observed; otherwise report it as not observed;425- bootstrap transaction phase and sanitized IDs, with `FINALIZED` required426 only after the separate fresh-evidence revocation gate;427- backup and tested rollback path.428429Production completion still requires live Galileo backend readback of the430Agent/Tool/LLM hierarchy. Static validation, collector acceptance, and an empty431or healthy queue do not substitute for that deployment gate.432433HTTP 200 alone is insufficient: OTLP responses can contain434`partialSuccess.rejectedSpans`, and collector counters do not prove backend435storage.