Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b0efcb2
feat(telemetry): add the Level 3 content-capture gate
dhshah13 Aug 20, 2026
0747767
feat(telemetry): add runtime-agnostic conversation content collector
dhshah13 Aug 20, 2026
40be09a
feat(telemetry): lift the span attribute cap when content capture is on
dhshah13 Aug 20, 2026
f1e5c6e
feat(telemetry): attach conversation content to the agent span
dhshah13 Aug 20, 2026
74368ea
docs(tracing): document Level 3 content capture and its boundaries
dhshah13 Aug 20, 2026
d7b6e46
docs(tracing): note MLflow preview derivation and backend size valida…
dhshah13 Aug 20, 2026
003fc2c
fix(telemetry): conform content capture to the output-messages schema
dhshah13 Aug 20, 2026
b304682
docs(tracing): correct content-capture contract wording
dhshah13 Aug 20, 2026
1a7c962
fix(telemetry): redact content before eviction cuts and discards
dhshah13 Aug 20, 2026
fa73a83
fix(telemetry): warn when an operator attr limit will cut content JSON
dhshah13 Aug 20, 2026
25ccef5
docs(tracing): state the consequence of a finite operator attr limit
dhshah13 Aug 20, 2026
d0a935c
test(telemetry): cover the tail-boundary fits case
dhshah13 Aug 20, 2026
1bf9bbf
fix(telemetry): bound agent-name span attributes at their call sites
dhshah13 Aug 20, 2026
abfcadb
docs(tracing): mark planned features with the Planned callout convention
dhshah13 Aug 20, 2026
c11233e
ci: forward the Level 3 content-capture gate to managed agent steps
dhshah13 Aug 21, 2026
848bad0
docs(tracing): tighten the Level 3 guide per review and add the enabl…
dhshah13 Aug 21, 2026
b806b87
docs(tracing): list the content-capture gate in GHA workflow configur…
dhshah13 Aug 21, 2026
94c3c4b
docs(tracing): reflect runner-composed retry prompts after #6502
dhshah13 Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/reusable-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: code
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/reusable-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: triage
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -817,6 +818,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: code
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -936,6 +938,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: review
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1206,6 +1209,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: fix
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1308,6 +1312,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: retro
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1395,6 +1400,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: prioritize
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1720,6 +1726,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
JIRA_TOKEN: ${{ secrets.JIRA_TOKEN }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_BASE_URL: ${{ inputs.jira_base_url || vars.JIRA_BASE_URL }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-fix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: fix
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-prioritize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: prioritize
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-retro.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: retro
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: review
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ jobs:
OTEL_EXPORTER_OTLP_CERTIFICATE: ${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}
OTEL_RESOURCE_ATTRIBUTES: ${{ vars.OTEL_RESOURCE_ATTRIBUTES }}
OTEL_SDK_DISABLED: ${{ vars.OTEL_SDK_DISABLED }}
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: ${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}
with:
agent: triage
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
37 changes: 37 additions & 0 deletions docs/guides/dev/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,43 @@ build the attribute slices. Start attributes: `iteration`,
`exit_code`, `gen_ai.system`, model, token counts, `fullsend.cost_usd`,
`fullsend.tool_calls`.

### Level 3 content on agent spans

When the content-capture gate is on
(`telemetry.ContentCaptureEnabled()`), `runAgent` constructs one
`contentCollector` per iteration — iteration and agent span are 1:1, so a
run-scoped collector would repeat earlier iterations' content on later
spans — and tees the runtime's normalized event stream to it through
`RunParams.OnEvent`.

**The tee trap:** supplying any `OnEvent` replaces the runtime's default
console renderer (`internal/runtime/claude.go`), so the handler built by
`contentEventHandler` always calls the renderer first and the collector
second. With the gate off the collector is nil and `contentEventHandler`
returns nil, leaving the default renderer path byte-identical to before
Level 3 existed.

The collector (`internal/cli/content_collector.go`) coalesces contiguous
text/reasoning deltas, maps tool use to `tool_call` parts, redacts every
part through `security.OutputPipeline()` at assembly (redaction runs
before the size budget — truncating first could split a secret past
recognition), enforces a 256 KiB ordered-suffix budget (the ending survives — the
final answer is what consumers judge) with exact dropped-byte accounting
across content, tool names, and summaries, and emits
`gen_ai.output.messages` JSON following the GenAI output-messages schema,
including the schema-required `finish_reason` from the iteration outcome. `attachContent` records the
content and its marker attributes on the span before either
`finalizeAgentSpan` path can end it, so failed iterations keep their
content.

**Consumer contract** (for eval scorers and other readers of
`run-telemetry.jsonl`): parse the `gen_ai.output.messages` attribute as
JSON; check `fullsend.content.truncated` / `fullsend.content.dropped_bytes`
before treating content as complete; masked secrets appear as the
redactor's mask tokens and are counted in `fullsend.content.redactions`.
The attribute names and shapes above are the consumption contract — see the
[Tracing reference](../infrastructure/distributed-tracing.md#content-capture-level-3).

## Trace identity and TRACEPARENT propagation

`resolveTraceIdentity()` handles W3C trace context propagation in three
Expand Down
66 changes: 55 additions & 11 deletions docs/guides/infrastructure/distributed-tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ For implementation details, see the
|-------|-----------------|----------------------|
| 1 | `run-telemetry.jsonl` file in the run output directory | None |
| 2 | OTLP/HTTP export to a remote backend (metadata only) | `OTEL_EXPORTER_OTLP_*ENDPOINT` |
| 3 | Content capture (prompts, completions, tool I/O) in spans | `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true` *(planned, not yet implemented)* |
| 3 | Conversation content (assistant text, reasoning, tool calls) on `agent` spans | `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true` |

All levels produce metadata (timing, token counts, tool names, errors).
Level 3 adds prompt/completion content to spans.
Level 3 adds the agent's conversation content to spans — enabled by one
environment variable, exactly like Level 2's endpoint.

## Environment variables

Expand Down Expand Up @@ -66,15 +67,52 @@ unset OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
| `TRACEPARENT` | W3C Trace Context parent | When present, the root span becomes `SpanKindConsumer`; when the sampled flag is unset (`-00`), OTLP export is suppressed but the local file is still written |
| `TRACESTATE` | W3C Trace Context state | Propagated alongside `TRACEPARENT` |

### Content capture (planned)

| Variable | Value | Effect |
|----------|-------|--------|
| `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` | `true` | Includes prompts, completions, tool arguments, tool results, and reasoning text in spans |

Content capture follows the [OTel GenAI semantic conventions](https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/gen-ai/gen-ai-spans.md).
When enabled, spans may contain proprietary source code, PII, or
credentials visible in tool outputs.
### Content capture (Level 3)

Fullsend assembles Level 3 content from the normalized event stream the
console renders, redacts it through the security output pipeline, and
attaches it to the per-iteration `agent` span. The agent runtime's own
content-logging variables (`OTEL_LOG_USER_PROMPTS`,
`OTEL_LOG_ASSISTANT_RESPONSES`, etc.) are never set.

| Variable | Values that enable capture | Values that keep it off |
|----------|---------------------------|-------------------------|
| `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` | `true`, `span_only`, `span_and_event` (case-insensitive) | unset, `false`, `NO_CONTENT`, `event_only`, anything unrecognized |

The variable name and accepted values follow the
[OpenTelemetry GenAI instrumentation convention](https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation-genai).
Fullsend records content on span attributes only, so `event_only` stays
off. An unrecognized value disables capture; telemetry never fails a run.

**Captured:** assistant text, reasoning, and tool calls (name plus short
summary) — including any sub-agent activity, unattributed — as the
`gen_ai.output.messages` span attribute: a JSON string following the
[GenAI output-messages schema](https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/gen-ai/gen-ai-output-messages.json)
with a `finish_reason` of `stop` or `error`.

**Not captured:** model input (`gen_ai.input.messages`) and
pre/post-script content. First-iteration runs have no meaningful
runner-side input; retry iterations carry the injected validation
feedback, a natural input-capture follow-up.

> **Planned:** Tool results, once a parser extension adds them to the
> normalized event stream — the next change after
> [#6429](https://github.com/fullsend-ai/fullsend/pull/6429).

**Redaction and size:** every part passes through security redaction
(Unicode normalization, then secret masking) before reaching the span.
Content is bounded at 256 KiB per iteration, kept as an ordered suffix;
overflow drops the oldest content first. Truncation is marked via
`fullsend.content.truncated`. The SDK's span attribute length cap is
lifted while capture is on; an explicit
`OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` still wins and will cut content
mid-JSON — fullsend warns on stderr at startup.

**Sinks:** content rides the span to both `run-telemetry.jsonl` and the
OTLP endpoint (when configured). Spans may contain proprietary source
code, PII, or credentials; the organization enabling capture is
responsible for its backend's access controls. For how MLflow displays
the content, see [Tracing with MLflow](../user/tracing-with-mlflow.md).

## Span hierarchy

Expand Down Expand Up @@ -126,6 +164,10 @@ and are recognized by LLM-aware backends for GenAI dashboards.
| `fullsend.prescript.skipped` | `run` | Whether the pre-script signaled a skip |
| `fullsend.prescript.skip_reason` | `run` | Human-readable skip reason from the pre-script |
| `fullsend.transcript_error` | `agent` | Present (`true`) when the agent exited 0 but its transcript reported an error — the span's status is Error while `exit_code` keeps the raw process exit |
| `gen_ai.output.messages` | `agent` | Level 3 only: the iteration's conversation content as a JSON string (see Content capture) |
| `fullsend.content.truncated` | `agent` | Level 3 only: present (`true`) when the size budget cut or dropped content |
| `fullsend.content.dropped_bytes` | `agent` | Level 3 only: exact content bytes removed by the size budget |
| `fullsend.content.redactions` | `agent` | Level 3 only: number of security findings raised while redacting content at assembly (including findings from parts the size budget later dropped) |

### Common attributes

Expand Down Expand Up @@ -218,6 +260,7 @@ that hosts the fullsend caller workflows:
| `OTEL_EXPORTER_OTLP_CERTIFICATE` | Variable | No | Path to a PEM CA bundle for backends behind a private CA. Commit the bundle into the config repo (e.g. `.fullsend/otel-ca.pem`) and set the variable to that checkout-relative path. |
| `OTEL_RESOURCE_ATTRIBUTES` | Variable | No | Static `k=v,k=v` trace tags. The value is used verbatim; `${{ github.* }}` expressions evaluate only in workflow YAML, not in variables. |
| `OTEL_SDK_DISABLED` | Variable | No | Set to `true` to disable all telemetry, including the local file exporter. |
| `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` | Variable | No | Set to `true` to attach conversation content to `agent` spans (Level 3; see Content capture). |

Installations scaffolded before OTEL support was added must also forward the
secrets (add `OTEL_EXPORTER_OTLP_TRACES_HEADERS` and
Expand All @@ -237,6 +280,7 @@ env:
OTEL_EXPORTER_OTLP_HEADERS: "${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}"
OTEL_RESOURCE_ATTRIBUTES: "${{ vars.OTEL_RESOURCE_ATTRIBUTES }}"
OTEL_SDK_DISABLED: "${{ vars.OTEL_SDK_DISABLED }}"
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "${{ vars.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT }}"
OTEL_EXPORTER_OTLP_CERTIFICATE: "${{ vars.OTEL_EXPORTER_OTLP_CERTIFICATE }}"
```

Expand Down
12 changes: 12 additions & 0 deletions docs/guides/user/how-to-emit-traces.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ to a backend like MLflow, Jaeger, Grafana Tempo, etc.
--org <org> --repos repo1,repo2,repo3
```

## Capture conversation content

Set `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` to add the agent's
text, reasoning, and tool calls to each `agent` span, in the local file and
at the endpoint. Content is redacted for secrets and bounded per iteration,
but may still contain proprietary code or PII — make sure your backend's
access controls fit before enabling it.

```bash
gh variable set OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT --body "true" --repo <owner/repo>
```

## Disable trace export

Remove the endpoint variable and header secret from the repository or
Expand Down
10 changes: 10 additions & 0 deletions docs/guides/user/tracing-with-mlflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ excludes cache-creation and cache-read tokens, which dominate agent-run cost.
The authoritative cost figure is the runtime-reported `fullsend.cost_usd`
attribute on `agent` spans (also in `run-telemetry.jsonl`).

## Level 3 content

With content capture enabled (see
[How To Emit Traces](how-to-emit-traces.md#capture-conversation-content)),
the conversation lives on each `agent` span as `gen_ai.output.messages`:
open the trace and select the span to read it. The trace list's
Request/Response preview columns derive from the root span only (capped
at 1000 characters), so they stay empty for fullsend traces — content is
deliberately not duplicated onto the root span.

## Local development

Start a local MLflow instance and point the exporter at it:
Expand Down
1 change: 1 addition & 0 deletions docs/problems/security-threat-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,4 @@ Issue [#1685](https://github.com/fullsend-ai/fullsend/issues/1685) explores usin
6. **Immutable agent policy** — agent rules cannot be modified through the channels agents operate on
7. **No agent self-modification** — agents cannot change their own configuration, permissions, or system prompts
8. **Verify, don't trust** — system state must be checked independently of agent self-reports (see [agent self-report unreliability](#cross-cutting-concern-agent-self-report-unreliability))
9. **Telemetry content boundary** — fullsend's content-handling guarantees (redaction at assembly, size bounds, opt-in gating) apply to its own extraction and redaction pipeline only; the agent runtime's native OTel instrumentation inside the sandbox is out of scope, like any other in-sandbox capability
Loading
Loading