@senad-d/observme 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +57 -0
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/ObservMe-Production-Docs/00-README.md +79 -0
- package/ObservMe-Production-Docs/01-requirements-and-scope.md +207 -0
- package/ObservMe-Production-Docs/02-reference-architecture.md +306 -0
- package/ObservMe-Production-Docs/03-pi-event-and-session-model.md +266 -0
- package/ObservMe-Production-Docs/04-telemetry-semantic-conventions.md +722 -0
- package/ObservMe-Production-Docs/05-otel-pipeline-and-collector.md +355 -0
- package/ObservMe-Production-Docs/06-security-privacy-redaction.md +294 -0
- package/ObservMe-Production-Docs/07-extension-implementation-blueprint.md +447 -0
- package/ObservMe-Production-Docs/08-query-grafana-integration.md +276 -0
- package/ObservMe-Production-Docs/09-dashboards-alerts-slos.md +640 -0
- package/ObservMe-Production-Docs/10-testing-release-operations.md +319 -0
- package/ObservMe-Production-Docs/11-deployment-runbooks.md +203 -0
- package/ObservMe-Production-Docs/12-configuration-reference.md +337 -0
- package/ObservMe-Production-Docs/13-source-notes.md +33 -0
- package/ObservMe-Production-Docs/pi-session-format.md +427 -0
- package/README.md +356 -0
- package/SECURITY.md +45 -0
- package/dashboards/observme-agent-node-graphs.json +250 -0
- package/dashboards/observme-agents.json +1880 -0
- package/dashboards/observme-alerts.yaml +113 -0
- package/dashboards/observme-branches-compactions.json +1042 -0
- package/dashboards/observme-cost.json +1254 -0
- package/dashboards/observme-errors.json +1659 -0
- package/dashboards/observme-export-health.json +1802 -0
- package/dashboards/observme-latency.json +1494 -0
- package/dashboards/observme-llm-conversations.json +730 -0
- package/dashboards/observme-logs-llm.json +644 -0
- package/dashboards/observme-models.json +933 -0
- package/dashboards/observme-overview.json +2129 -0
- package/dashboards/observme-slo-health.json +737 -0
- package/dashboards/observme-slos.yaml +56 -0
- package/dashboards/observme-tools.json +902 -0
- package/dashboards/observme-trace-journey.json +1793 -0
- package/docs/STRUCTURE.md +49 -0
- package/docs/agent-subagent-observability-requirements.md +997 -0
- package/docs/compatibility-matrix.md +39 -0
- package/docs/configuration-tui-design-standard.md +767 -0
- package/docs/configuration.md +38 -0
- package/docs/review-validation.md +115 -0
- package/docs/validation-flow.md +117 -0
- package/examples/collector.yaml +123 -0
- package/examples/observme.yaml +131 -0
- package/img/demo.gif +0 -0
- package/img/icon.svg +47 -0
- package/package.json +103 -0
- package/src/commands/obs-agents-runtime.ts +150 -0
- package/src/commands/obs-agents.ts +491 -0
- package/src/commands/obs-args.ts +63 -0
- package/src/commands/obs-backfill.ts +1334 -0
- package/src/commands/obs-command-support.ts +43 -0
- package/src/commands/obs-cost.ts +228 -0
- package/src/commands/obs-diagnostics.ts +22 -0
- package/src/commands/obs-errors.ts +156 -0
- package/src/commands/obs-health.ts +301 -0
- package/src/commands/obs-link.ts +90 -0
- package/src/commands/obs-logs.ts +194 -0
- package/src/commands/obs-loki-summary.ts +184 -0
- package/src/commands/obs-session.ts +259 -0
- package/src/commands/obs-status.ts +359 -0
- package/src/commands/obs-tools.ts +274 -0
- package/src/commands/obs-trace.ts +411 -0
- package/src/commands/obs.ts +211 -0
- package/src/config/bootstrap-project-config.ts +300 -0
- package/src/config/defaults.ts +143 -0
- package/src/config/load-config.ts +631 -0
- package/src/config/project-paths.ts +61 -0
- package/src/config/schema.ts +405 -0
- package/src/config/validate.ts +456 -0
- package/src/constants.ts +4 -0
- package/src/diagnostics/sanitize.ts +6 -0
- package/src/extension.ts +38 -0
- package/src/otel/logs.ts +160 -0
- package/src/otel/metrics.ts +165 -0
- package/src/otel/otlp-endpoint.ts +10 -0
- package/src/otel/sdk.ts +114 -0
- package/src/otel/shutdown.ts +102 -0
- package/src/otel/traces.ts +166 -0
- package/src/pi/agent-lineage.ts +378 -0
- package/src/pi/agent-tree-tracker.ts +258 -0
- package/src/pi/event-handlers/agent-turn.ts +155 -0
- package/src/pi/event-handlers/lifecycle.ts +642 -0
- package/src/pi/event-handlers/llm.ts +115 -0
- package/src/pi/event-handlers/session-events.ts +159 -0
- package/src/pi/event-handlers/tool-bash.ts +275 -0
- package/src/pi/handler-internals.ts +2154 -0
- package/src/pi/handler-runtime.ts +633 -0
- package/src/pi/handler-types.ts +261 -0
- package/src/pi/handlers.ts +75 -0
- package/src/pi/subagent-spawn.ts +975 -0
- package/src/pi/subagent-types.ts +29 -0
- package/src/privacy/content-capture.ts +104 -0
- package/src/privacy/hash.ts +93 -0
- package/src/privacy/redact.ts +619 -0
- package/src/privacy/secret-patterns.ts +185 -0
- package/src/privacy/truncate.ts +69 -0
- package/src/query/grafana-readiness.ts +164 -0
- package/src/query/grafana-transport.ts +481 -0
- package/src/query/grafana.ts +371 -0
- package/src/query/loki.ts +332 -0
- package/src/query/prometheus.ts +388 -0
- package/src/query/tempo.ts +332 -0
- package/src/safety/sensitive-input.ts +208 -0
- package/src/semconv/attributes.ts +279 -0
- package/src/semconv/metrics.ts +146 -0
- package/src/semconv/spans.ts +19 -0
- package/src/semconv/values.ts +13 -0
- package/src/util/bounded-map.ts +97 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
# Agent and Subagent Orchestration Observability Requirements
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This document explains what ObservMe and a future Pi agent-orchestration extension need in order to run, manage, and observe root agents and subagents correctly.
|
|
6
|
+
|
|
7
|
+
The target runtime model is explicit: subagents are isolated Pi processes, often started inside dedicated `tmux` sessions, and every child/subagent Pi process is expected to load the ObservMe extension too. Tmux isolation is compatible with ObservMe, but tmux does not create lineage by itself. The orchestration extension must launch tmux with ObservMe lineage and trace-context environment variables, then record spawn, wait, join, status, and cleanup telemetry.
|
|
8
|
+
|
|
9
|
+
It is documentation-only. It does not change runtime behavior.
|
|
10
|
+
|
|
11
|
+
## Sources reviewed
|
|
12
|
+
|
|
13
|
+
Project sources:
|
|
14
|
+
|
|
15
|
+
- `README.md`
|
|
16
|
+
- `ObservMe-Production-Docs/01-requirements-and-scope.md`
|
|
17
|
+
- `ObservMe-Production-Docs/02-reference-architecture.md`
|
|
18
|
+
- `ObservMe-Production-Docs/03-pi-event-and-session-model.md`
|
|
19
|
+
- `ObservMe-Production-Docs/04-telemetry-semantic-conventions.md`
|
|
20
|
+
- `ObservMe-Production-Docs/06-security-privacy-redaction.md`
|
|
21
|
+
- `ObservMe-Production-Docs/07-extension-implementation-blueprint.md`
|
|
22
|
+
- `ObservMe-Production-Docs/09-dashboards-alerts-slos.md`
|
|
23
|
+
- `ObservMe-Production-Docs/10-testing-release-operations.md`
|
|
24
|
+
- `ObservMe-Production-Docs/12-configuration-reference.md`
|
|
25
|
+
- `src/pi/agent-lineage.ts`
|
|
26
|
+
- `src/pi/agent-tree-tracker.ts`
|
|
27
|
+
- `src/pi/subagent-spawn.ts`
|
|
28
|
+
- `src/pi/handlers.ts`
|
|
29
|
+
- `src/pi/handler-internals.ts`
|
|
30
|
+
- `src/commands/obs-agents.ts`
|
|
31
|
+
- `src/commands/obs-agents-runtime.ts`
|
|
32
|
+
- `src/config/defaults.ts`
|
|
33
|
+
- `src/config/schema.ts`
|
|
34
|
+
- `src/config/validate.ts`
|
|
35
|
+
- `src/semconv/attributes.ts`
|
|
36
|
+
- `src/semconv/metrics.ts`
|
|
37
|
+
- `dashboards/observme-agents.json`
|
|
38
|
+
- `dashboards/observme-overview.json`
|
|
39
|
+
- `dashboards/observme-trace-journey.json`
|
|
40
|
+
- `dashboards/observme-alerts.yaml`
|
|
41
|
+
- `dashboards/observme-slos.yaml`
|
|
42
|
+
- `examples/observme.yaml`
|
|
43
|
+
- `examples/collector.yaml`
|
|
44
|
+
- `test/agent-lineage.test.ts`
|
|
45
|
+
- `test/subagent-spawn.test.mjs`
|
|
46
|
+
|
|
47
|
+
Pi documentation and examples:
|
|
48
|
+
|
|
49
|
+
- Pi `README.md`
|
|
50
|
+
- Pi `docs/extensions.md`
|
|
51
|
+
- Pi `docs/session-format.md`
|
|
52
|
+
- Pi `docs/sessions.md`
|
|
53
|
+
- Pi `docs/packages.md`
|
|
54
|
+
- Pi `examples/extensions/subagent/README.md`
|
|
55
|
+
- Pi `examples/extensions/subagent/index.ts`
|
|
56
|
+
- Pi `examples/extensions/subagent/agents.ts`
|
|
57
|
+
|
|
58
|
+
## Target outcome for the orchestration extension
|
|
59
|
+
|
|
60
|
+
The future orchestration extension should provide the complete control plane for agent and subagent work:
|
|
61
|
+
|
|
62
|
+
- discover and validate agent definitions
|
|
63
|
+
- start root-like managed agents and child subagents
|
|
64
|
+
- launch isolated subagent Pi processes inside tmux sessions
|
|
65
|
+
- ensure every child Pi process loads ObservMe
|
|
66
|
+
- propagate ObservMe workflow, parent/root agent lineage, spawn id, session id, and W3C trace context into the child process
|
|
67
|
+
- distinguish root agents, subagents, and orphan agents deterministically
|
|
68
|
+
- list, inspect, attach to, detach from, stop, and clean up tmux-backed agents
|
|
69
|
+
- send tasks or follow-up messages to running child agents when the selected execution mode supports it
|
|
70
|
+
- record spawn, wait, join, cancellation, timeout, child failure, and recovery telemetry
|
|
71
|
+
- keep high-cardinality identifiers out of Prometheus metric labels
|
|
72
|
+
- expose enough local state for `/obs agents` and enough exported telemetry for Grafana dashboards
|
|
73
|
+
|
|
74
|
+
Current state: ObservMe already has lineage, agent-tree, spawn, wait/join, dashboard, and `/obs agents` building blocks, but subagent dashboards are not fully automatic for arbitrary child Pi processes or tmux sessions. Full dashboard behavior requires an ObservMe-aware orchestration launcher.
|
|
75
|
+
|
|
76
|
+
## 1. Terminology
|
|
77
|
+
|
|
78
|
+
### Pi agent runtime
|
|
79
|
+
|
|
80
|
+
A Pi agent runtime is one running Pi process/session that emits Pi lifecycle events such as:
|
|
81
|
+
|
|
82
|
+
- `session_start`
|
|
83
|
+
- `agent_start`
|
|
84
|
+
- `turn_start`
|
|
85
|
+
- `before_provider_request`
|
|
86
|
+
- `tool_execution_start`
|
|
87
|
+
- `tool_call`
|
|
88
|
+
- `tool_result`
|
|
89
|
+
- `turn_end`
|
|
90
|
+
- `agent_end`
|
|
91
|
+
- `session_shutdown`
|
|
92
|
+
|
|
93
|
+
In ObservMe, this runtime gets a logical identity:
|
|
94
|
+
|
|
95
|
+
- `pi.agent.id`
|
|
96
|
+
- `pi.agent.root_id`
|
|
97
|
+
- `pi.agent.parent_id` when it is a child
|
|
98
|
+
- `pi.agent.depth`
|
|
99
|
+
- `pi.agent.role`
|
|
100
|
+
|
|
101
|
+
### Agent run
|
|
102
|
+
|
|
103
|
+
A Pi `agent_start` / `agent_end` pair is one user-prompt lifecycle inside a Pi runtime. ObservMe represents this as a `pi.agent.run` span.
|
|
104
|
+
|
|
105
|
+
Important distinction:
|
|
106
|
+
|
|
107
|
+
- `pi.agent.id` identifies the logical runtime.
|
|
108
|
+
- `pi.agent.run.id` identifies one prompt lifecycle inside that runtime.
|
|
109
|
+
|
|
110
|
+
Dashboard panels such as `observme_agent_runs_total` count `agent_start` / `agent_end` lifecycles, not process spawns.
|
|
111
|
+
|
|
112
|
+
### Pi subagent
|
|
113
|
+
|
|
114
|
+
Pi core does not have built-in subagents. The Pi docs state that subagents are created by extensions or packages. The official example subagent extension launches separate `pi` subprocesses in JSON/print mode so each delegated agent has an isolated context window.
|
|
115
|
+
|
|
116
|
+
In ObservMe, a subagent is a separate Pi runtime that has trusted parent lineage:
|
|
117
|
+
|
|
118
|
+
- `pi.agent.parent_id` is set.
|
|
119
|
+
- `pi.agent.root_id` is inherited from the original root agent.
|
|
120
|
+
- `pi.workflow.id` is inherited from the original workflow.
|
|
121
|
+
- `pi.agent.depth` is parent depth plus one.
|
|
122
|
+
- `pi.agent.role` is usually `subagent` unless explicitly set to a bounded role such as `worker` or `reviewer`.
|
|
123
|
+
|
|
124
|
+
### Pi subagent agent definitions
|
|
125
|
+
|
|
126
|
+
The Pi subagent example uses markdown agent definitions such as:
|
|
127
|
+
|
|
128
|
+
- `~/.pi/agent/agents/*.md`
|
|
129
|
+
- `.pi/agents/*.md`
|
|
130
|
+
|
|
131
|
+
Each definition has frontmatter like `name`, `description`, `tools`, and `model`, plus a system prompt body.
|
|
132
|
+
|
|
133
|
+
These markdown agent names are not automatically the same thing as ObservMe `pi.agent.id` or `pi.agent.role`. For observability they should be treated as safe capability/role metadata only if mapped intentionally, for example:
|
|
134
|
+
|
|
135
|
+
- `OBSERVME_AGENT_CAPABILITY=scout`
|
|
136
|
+
- `agent_capability="scout"`
|
|
137
|
+
- `agent_role="worker"` or `agent_role="reviewer"`
|
|
138
|
+
|
|
139
|
+
Do not use markdown agent names as high-cardinality identifiers.
|
|
140
|
+
|
|
141
|
+
### Tmux-managed subagent
|
|
142
|
+
|
|
143
|
+
A tmux-managed subagent is a child Pi process started in its own tmux session or pane. It is still just a Pi subagent from ObservMe's perspective. Tmux provides process isolation, attach/detach behavior, and operator control, but it does not provide ObservMe lineage.
|
|
144
|
+
|
|
145
|
+
Required tmux-managed subagent properties:
|
|
146
|
+
|
|
147
|
+
- It runs a normal Pi command inside tmux.
|
|
148
|
+
- It loads ObservMe through an installed package, project/user extension discovery, or an explicit `-e` extension source.
|
|
149
|
+
- It receives ObservMe lineage and trace env from the parent launcher.
|
|
150
|
+
- It exports telemetry to the same or compatible OTLP backend as the parent.
|
|
151
|
+
- It has a predictable tmux session/window/pane name so the orchestration extension can list, attach, stop, and clean it up.
|
|
152
|
+
|
|
153
|
+
Recommended naming pattern:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
observme-<workflow-short>-<agent-name>-<spawn-short>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The full workflow id, agent id, spawn id, and session id remain trace/log attributes only. Do not use them as Prometheus labels.
|
|
160
|
+
|
|
161
|
+
## 2. How to know root agent vs subagent
|
|
162
|
+
|
|
163
|
+
ObservMe decides agent lineage from trusted propagated context.
|
|
164
|
+
|
|
165
|
+
### Root-like agent
|
|
166
|
+
|
|
167
|
+
A runtime is root-like when no trusted parent context is accepted.
|
|
168
|
+
|
|
169
|
+
Expected fields:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
pi.agent.role = root
|
|
173
|
+
pi.agent.depth = 0
|
|
174
|
+
pi.agent.parent_id is absent
|
|
175
|
+
pi.agent.root_id = pi.agent.id
|
|
176
|
+
pi.workflow.root_agent_id = pi.agent.id
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Subagent
|
|
180
|
+
|
|
181
|
+
A runtime is a subagent when it accepts trusted parent lineage.
|
|
182
|
+
|
|
183
|
+
Expected fields:
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
pi.agent.role = subagent
|
|
187
|
+
pi.agent.parent_id = <parent pi.agent.id>
|
|
188
|
+
pi.agent.root_id = <root pi.agent.id>
|
|
189
|
+
pi.workflow.id = <parent workflow id>
|
|
190
|
+
pi.workflow.root_agent_id = <root pi.agent.id>
|
|
191
|
+
pi.agent.depth = <parent depth> + 1
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Orphan subagent
|
|
195
|
+
|
|
196
|
+
A runtime is orphaned when some parent lineage is present but the root/parent linkage is incomplete or cannot be connected to a known parent.
|
|
197
|
+
|
|
198
|
+
Expected behavior:
|
|
199
|
+
|
|
200
|
+
- Emit `agent.orphaned` log/event.
|
|
201
|
+
- Increment `observme_orphan_agents_total`.
|
|
202
|
+
- Keep Pi running fail-open.
|
|
203
|
+
- Do not place raw environment values or raw command lines into telemetry.
|
|
204
|
+
|
|
205
|
+
### Current production rule
|
|
206
|
+
|
|
207
|
+
The shipped extension registers session handlers with `trustedParentContext: true`, making the Pi process environment eligible for launcher-provided lineage. Trusted project `.env` values are loaded into ObservMe configuration but are not copied into this lineage input, so a project file cannot establish parent provenance.
|
|
208
|
+
|
|
209
|
+
Eligibility is not blind acceptance. When any propagation value is present, `src/pi/agent-lineage.ts` requires a complete validated workflow, parent agent, root agent, parent depth, and spawn envelope. Trace-enabled propagation also requires valid W3C `traceparent`; optional `tracestate` and duplicate parent trace/span metadata must validate and agree. A stale inherited child agent id is rejected. Partial, malformed, oversized, or stale envelopes fail open to root/orphan lineage with bounded diagnostics that never include raw inherited values.
|
|
210
|
+
|
|
211
|
+
ObservMe validates the process envelope but does not cryptographically authenticate the launcher. An ObservMe-aware launcher remains responsible for constructing the envelope immediately before child startup and clearing stale propagation variables. Explicit runtime lineage options remain available to tests and embedders.
|
|
212
|
+
|
|
213
|
+
For tmux orchestration this is the critical distinction:
|
|
214
|
+
|
|
215
|
+
- **Child Pi with ObservMe but no propagation envelope:** telemetry exists and the child starts as a root-like runtime.
|
|
216
|
+
- **Child Pi with a complete validated process envelope:** telemetry joins the parent workflow and continues the propagated W3C trace.
|
|
217
|
+
- **Child Pi with a partial/broken/stale envelope:** Pi keeps running with root/orphan fallback and one bounded propagation-failure signal.
|
|
218
|
+
|
|
219
|
+
## 3. What ObservMe must do at a subagent spawn point
|
|
220
|
+
|
|
221
|
+
Pi does not emit a dedicated `subagent_spawned` event. ObservMe must instrument the exact code path that launches or waits for another Pi process.
|
|
222
|
+
|
|
223
|
+
The required parent-side flow is:
|
|
224
|
+
|
|
225
|
+
1. Parent is already inside an ObservMe session.
|
|
226
|
+
2. Parent extension/tool decides to launch a child Pi process.
|
|
227
|
+
3. ObservMe starts a `pi.agent.spawn` span.
|
|
228
|
+
4. ObservMe creates a spawn id: `pi.agent.spawn.id`.
|
|
229
|
+
5. ObservMe builds child environment variables containing workflow, parent/root agent, depth, spawn, session, and trace context.
|
|
230
|
+
6. The subagent launcher must pass that environment to `child_process.spawn` or an equivalent process runner.
|
|
231
|
+
7. Parent records spawn completion or failure.
|
|
232
|
+
8. Parent records `pi.agent.wait` when it waits for the child.
|
|
233
|
+
9. Parent records `pi.agent.join` when it receives the child result/status.
|
|
234
|
+
10. Parent updates the in-memory agent tree and `/obs agents` runtime state.
|
|
235
|
+
|
|
236
|
+
The existing helper module for this is `src/pi/subagent-spawn.ts`:
|
|
237
|
+
|
|
238
|
+
- `startSubagentSpawn(...)`
|
|
239
|
+
- `completeSubagentSpawn(...)`
|
|
240
|
+
- `failSubagentSpawn(...)`
|
|
241
|
+
- `runSubagentWithObservability(...)`
|
|
242
|
+
- `startAgentWait(...)` / `endAgentWait(...)`
|
|
243
|
+
- `startAgentJoin(...)` / `endAgentJoin(...)`
|
|
244
|
+
- `recordAgentWait(...)` / `recordAgentJoin(...)`
|
|
245
|
+
- `observeTrustedSubagentLineage(...)`
|
|
246
|
+
|
|
247
|
+
If a subagent extension launches `pi` without using these helpers, ObservMe can still observe the launcher as a normal tool call, but the agent/subagent dashboards will not get the full spawn/depth/fan-out/wait/join contract.
|
|
248
|
+
|
|
249
|
+
### Tmux-specific spawn requirements
|
|
250
|
+
|
|
251
|
+
When the child is launched through tmux, the orchestration extension must still treat tmux as the process runner around a child Pi process.
|
|
252
|
+
|
|
253
|
+
Required flow:
|
|
254
|
+
|
|
255
|
+
1. Start `pi.agent.spawn` before creating the tmux session.
|
|
256
|
+
2. Build the child environment from the started spawn state.
|
|
257
|
+
3. Start tmux with an explicit command that injects that environment into the child Pi process.
|
|
258
|
+
4. Do not rely on the tmux server's cached global environment; it may be stale if the tmux server was started earlier.
|
|
259
|
+
5. Store the tmux session/window/pane identifiers in local orchestration state and in safe span/log attributes when low-cardinality or hashed.
|
|
260
|
+
6. Mark spawn `completed` only when the tmux session/pane and child command were created successfully.
|
|
261
|
+
7. Mark spawn `failed` if tmux cannot be started, the pane exits before Pi starts, or the command cannot be delivered.
|
|
262
|
+
8. Record `wait` while the orchestrator is waiting for child completion or a child status signal.
|
|
263
|
+
9. Record `join` when the orchestrator collects a child result, sees a terminal child status, or times out.
|
|
264
|
+
|
|
265
|
+
Conceptual command shape:
|
|
266
|
+
|
|
267
|
+
```text
|
|
268
|
+
tmux new-session -d -s <safe-session-name> \
|
|
269
|
+
'env OBSERVME_WORKFLOW_ID=... OBSERVME_PARENT_AGENT_ID=... traceparent=... pi ...'
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The command above is illustrative only. The implementation must avoid logging the raw command because it contains environment values and user task text.
|
|
273
|
+
|
|
274
|
+
## 4. Environment propagation contract
|
|
275
|
+
|
|
276
|
+
When propagation is enabled, parent-to-child environment must include safe generated lineage values.
|
|
277
|
+
|
|
278
|
+
Configured default env names:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
OBSERVME_WORKFLOW_ID
|
|
282
|
+
OBSERVME_PARENT_AGENT_ID
|
|
283
|
+
OBSERVME_ROOT_AGENT_ID
|
|
284
|
+
OBSERVME_PARENT_SESSION_ID
|
|
285
|
+
OBSERVME_PARENT_TRACE_ID
|
|
286
|
+
OBSERVME_PARENT_SPAN_ID
|
|
287
|
+
OBSERVME_AGENT_DEPTH
|
|
288
|
+
OBSERVME_SPAWN_ID
|
|
289
|
+
OBSERVME_AGENT_CAPABILITY
|
|
290
|
+
traceparent
|
|
291
|
+
tracestate
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Important details:
|
|
295
|
+
|
|
296
|
+
- `OBSERVME_AGENT_ID` is not normally propagated from parent to child; the child should generate its own `pi.agent.id`.
|
|
297
|
+
- Inherited ObservMe and W3C propagation variables are cleared before current child lineage is written, so stale agent IDs, spawn IDs, parent trace/span IDs, `traceparent`, or `tracestate` never leak into a new child environment.
|
|
298
|
+
- `OBSERVME_AGENT_DEPTH` carries the parent depth. The child increments it when creating its own lineage.
|
|
299
|
+
- `traceparent` and `tracestate` let the child continue the same distributed trace when possible.
|
|
300
|
+
- If W3C trace context cannot be propagated, ObservMe must still propagate workflow/parent/root ids and emit fallback telemetry.
|
|
301
|
+
- Raw commands, prompts, cwd, usernames, hostnames, PIDs, and inherited environment values must not be used to derive lineage ids.
|
|
302
|
+
- In tmux mode, env propagation must be explicit per child command or per tmux session. Do not assume the parent process environment reaches a pane through an already-running tmux server.
|
|
303
|
+
- If the orchestrator stores tmux metadata, store only safe names, hashed values, or bounded status enums in telemetry.
|
|
304
|
+
|
|
305
|
+
Config gates:
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
workflow:
|
|
309
|
+
enabled: true
|
|
310
|
+
agent:
|
|
311
|
+
propagateTraceContext: true
|
|
312
|
+
propagateToSubagents: true
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Validation gates:
|
|
316
|
+
|
|
317
|
+
- Workflow, parent-agent, root-agent, depth, and spawn values must be present together when any propagated value is supplied.
|
|
318
|
+
- Lineage env values must be short and match the safe character pattern.
|
|
319
|
+
- Trace-enabled propagation must include a valid W3C `traceparent`; optional `tracestate` is bounded and structurally validated.
|
|
320
|
+
- Parent trace id must be 32 hex characters and parent span id must be 16 hex characters when duplicate metadata is supplied; both must match `traceparent`.
|
|
321
|
+
- Depth must be an integer between 0 and 64.
|
|
322
|
+
- A stale inherited child agent id or uppercase W3C propagation variable invalidates the envelope.
|
|
323
|
+
|
|
324
|
+
## 5. Child runtime contract
|
|
325
|
+
|
|
326
|
+
For child subagent telemetry to appear correctly:
|
|
327
|
+
|
|
328
|
+
1. The child process must load the ObservMe extension.
|
|
329
|
+
2. The child process must inherit the ObservMe propagation env from the parent wrapper.
|
|
330
|
+
3. The child ObservMe runtime must treat that env as trusted parent context.
|
|
331
|
+
4. The child must export traces, metrics, and logs to the same or compatible OTLP backend.
|
|
332
|
+
5. The Collector must preserve lineage attributes on traces/logs and drop high-cardinality lineage attributes from metric labels.
|
|
333
|
+
|
|
334
|
+
If the child process runs `pi --no-session`, it can still emit runtime telemetry, but durable Pi session-file recovery is not available. ObservMe should rely on live events and propagated lineage in that case.
|
|
335
|
+
|
|
336
|
+
## 5.1 Tmux-based orchestration extension requirements
|
|
337
|
+
|
|
338
|
+
This section is the implementation brief for the future Pi extension that manages agent orchestration.
|
|
339
|
+
|
|
340
|
+
### Responsibilities
|
|
341
|
+
|
|
342
|
+
The orchestration extension is responsible for:
|
|
343
|
+
|
|
344
|
+
- agent discovery and validation
|
|
345
|
+
- tmux session creation and naming
|
|
346
|
+
- ObservMe lineage and trace propagation
|
|
347
|
+
- child Pi command construction
|
|
348
|
+
- child ObservMe loading guarantees
|
|
349
|
+
- child task delivery
|
|
350
|
+
- child lifecycle/status tracking
|
|
351
|
+
- parent wait/join accounting
|
|
352
|
+
- cancellation/timeout handling
|
|
353
|
+
- attach/detach user workflows
|
|
354
|
+
- safe cleanup of completed or failed tmux sessions
|
|
355
|
+
- local `/obs agents` state updates and exported telemetry
|
|
356
|
+
|
|
357
|
+
The ObservMe telemetry layer is responsible for:
|
|
358
|
+
|
|
359
|
+
- spans, metrics, logs, and dashboards
|
|
360
|
+
- redaction and high-cardinality protection
|
|
361
|
+
- fail-open export behavior
|
|
362
|
+
- agent-tree and lineage semantics
|
|
363
|
+
|
|
364
|
+
Do not mix these responsibilities by putting orchestration secrets or raw commands into telemetry.
|
|
365
|
+
|
|
366
|
+
### Required execution modes
|
|
367
|
+
|
|
368
|
+
The extension should support at least these modes:
|
|
369
|
+
|
|
370
|
+
| Mode | Description | Best for | Join source |
|
|
371
|
+
|---|---|---|---|
|
|
372
|
+
| `tmux-interactive` | Start a normal interactive Pi TUI in tmux. Operators can attach and watch or steer. | Long-running isolated work. | tmux pane status, explicit completion marker, or operator action. |
|
|
373
|
+
| `tmux-print-json` | Start `pi --mode json -p` in tmux and capture stdout/stderr to files or pipes. | Automated delegated tasks with structured output. | process exit plus parsed JSON events. |
|
|
374
|
+
| `tmux-rpc` | Start Pi RPC mode in tmux or a supervised process and communicate through explicit pipes. | Long-lived managed agents. | RPC response/status protocol. |
|
|
375
|
+
|
|
376
|
+
For all modes, ObservMe lineage propagation is mandatory.
|
|
377
|
+
|
|
378
|
+
### Agent definition contract
|
|
379
|
+
|
|
380
|
+
Each manageable agent should have a bounded definition:
|
|
381
|
+
|
|
382
|
+
```yaml
|
|
383
|
+
name: scout
|
|
384
|
+
role: worker # root|subagent|orchestrator|worker|reviewer|unknown
|
|
385
|
+
capability: scout # bounded low-cardinality value
|
|
386
|
+
description: Fast codebase recon
|
|
387
|
+
model: claude-haiku-4-5
|
|
388
|
+
tools: read, grep, find, ls, bash
|
|
389
|
+
mode: tmux-print-json # tmux-interactive|tmux-print-json|tmux-rpc
|
|
390
|
+
cwdPolicy: parent # parent|explicit|project-root
|
|
391
|
+
maxRuntimeMs: 1800000
|
|
392
|
+
maxConcurrent: 4
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Rules:
|
|
396
|
+
|
|
397
|
+
- `name`, `role`, and `capability` must be normalized to bounded safe strings before use in telemetry.
|
|
398
|
+
- `name` may be shown in UI and tmux names, but it must not replace `pi.agent.id`.
|
|
399
|
+
- `role` and `capability` may become metric labels only if bounded by config validation.
|
|
400
|
+
- Project-local agent definitions require project trust and, in interactive mode, confirmation before execution.
|
|
401
|
+
|
|
402
|
+
### Child Pi command requirements
|
|
403
|
+
|
|
404
|
+
The child command must guarantee ObservMe loads in the child runtime.
|
|
405
|
+
|
|
406
|
+
Acceptable approaches:
|
|
407
|
+
|
|
408
|
+
- ObservMe is installed globally as a Pi package and extension discovery is enabled.
|
|
409
|
+
- ObservMe is installed project-locally and the project is trusted.
|
|
410
|
+
- The orchestrator explicitly passes `-e <observme-extension-source>` to the child Pi command.
|
|
411
|
+
|
|
412
|
+
The child command must not use `--no-extensions` unless it also explicitly loads ObservMe. If a mode requires `--no-extensions` for isolation, the command must add ObservMe back explicitly.
|
|
413
|
+
|
|
414
|
+
Recommended child command inputs:
|
|
415
|
+
|
|
416
|
+
```text
|
|
417
|
+
pi [observme-load-options] [mode-options] [model/tools options] [task]
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Examples of mode options:
|
|
421
|
+
|
|
422
|
+
```text
|
|
423
|
+
--mode json -p --no-session
|
|
424
|
+
--mode rpc
|
|
425
|
+
# or normal interactive mode inside tmux
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Do not include raw prompt/task text in exported telemetry. Use hashes, lengths, bounded status, or redacted content only when capture is explicitly enabled.
|
|
429
|
+
|
|
430
|
+
### Tmux session lifecycle
|
|
431
|
+
|
|
432
|
+
The orchestration extension should maintain a bounded in-memory registry for active tmux agents:
|
|
433
|
+
|
|
434
|
+
```text
|
|
435
|
+
spawn_id
|
|
436
|
+
workflow_id
|
|
437
|
+
parent_agent_id
|
|
438
|
+
child_agent_id when known
|
|
439
|
+
agent_name
|
|
440
|
+
agent_role
|
|
441
|
+
agent_capability
|
|
442
|
+
tmux_session_name
|
|
443
|
+
tmux_window_id / pane_id when available
|
|
444
|
+
status: starting|active|completed|failed|cancelled|timeout|orphaned
|
|
445
|
+
started_at
|
|
446
|
+
last_status_at
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Telemetry rules:
|
|
450
|
+
|
|
451
|
+
- `spawn_id`, `workflow_id`, `parent_agent_id`, `child_agent_id`, and session ids are span/log attributes only.
|
|
452
|
+
- `agent_role`, `agent_capability`, `subagent_depth`, `spawn_type`, `spawn_reason`, `status`, and `reason` may be metric labels when bounded.
|
|
453
|
+
- Tmux pane ids and raw session names should be treated as operational metadata; prefer span/log attributes or hashed values, not metric labels.
|
|
454
|
+
|
|
455
|
+
Lifecycle operations:
|
|
456
|
+
|
|
457
|
+
1. **Create**: validate agent definition, build lineage env, create tmux session, start child Pi.
|
|
458
|
+
2. **Activate**: mark child status active after tmux and Pi startup are confirmed.
|
|
459
|
+
3. **Wait**: record `pi.agent.wait` while parent waits for child output, exit, or status marker.
|
|
460
|
+
4. **Join**: record `pi.agent.join` with terminal status and result summary.
|
|
461
|
+
5. **Attach**: open or report the tmux attach command without exposing secrets.
|
|
462
|
+
6. **Detach**: leave child running and keep status active.
|
|
463
|
+
7. **Stop**: request graceful Pi shutdown first, then terminate tmux session after timeout.
|
|
464
|
+
8. **Cleanup**: remove completed tmux sessions according to retention policy.
|
|
465
|
+
|
|
466
|
+
### Management command surface
|
|
467
|
+
|
|
468
|
+
The future extension should expose commands or tools equivalent to:
|
|
469
|
+
|
|
470
|
+
```text
|
|
471
|
+
/agents list
|
|
472
|
+
/agents start <agent> [task]
|
|
473
|
+
/agents status [agent|spawn]
|
|
474
|
+
/agents attach <agent|spawn>
|
|
475
|
+
/agents send <agent|spawn> <message>
|
|
476
|
+
/agents wait <agent|spawn>
|
|
477
|
+
/agents join <agent|spawn>
|
|
478
|
+
/agents stop <agent|spawn>
|
|
479
|
+
/agents cleanup
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
If this is folded under ObservMe commands, use `/obs agents` only for observability and add a separate orchestration namespace for mutations. `/obs` query commands should remain read-only.
|
|
483
|
+
|
|
484
|
+
LLM-facing tools should be separate from user commands and must have clear schemas, prompt snippets, and prompt guidelines. Tool names must explicitly identify the tool in every guideline.
|
|
485
|
+
|
|
486
|
+
### Result and status collection
|
|
487
|
+
|
|
488
|
+
The extension must define how a parent knows a tmux subagent has completed.
|
|
489
|
+
|
|
490
|
+
Allowed approaches:
|
|
491
|
+
|
|
492
|
+
- child process exits and the orchestrator captures exit status
|
|
493
|
+
- child writes a small status/result file with redacted/structured summary
|
|
494
|
+
- child emits JSON events that the orchestrator reads from a pipe/log
|
|
495
|
+
- child is controlled through RPC and returns an explicit response
|
|
496
|
+
- operator marks a tmux-interactive child as joined/cancelled
|
|
497
|
+
- backend query confirms terminal telemetry, with timeout fallback
|
|
498
|
+
|
|
499
|
+
The parent `join` record should include:
|
|
500
|
+
|
|
501
|
+
```text
|
|
502
|
+
child status: ok|error|cancelled|timeout|partial|unknown
|
|
503
|
+
failure propagated: true|false
|
|
504
|
+
active children count
|
|
505
|
+
child count / fan-out count
|
|
506
|
+
safe result summary hash/length when available
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Trust model for propagated lineage
|
|
510
|
+
|
|
511
|
+
The implemented trust boundary is the child Pi process environment plus a complete generated spawn envelope:
|
|
512
|
+
|
|
513
|
+
1. The parent creates a fresh `OBSERVME_SPAWN_ID` and validated workflow/parent/root/depth values around the `pi.agent.spawn` span.
|
|
514
|
+
2. The launcher passes those values and W3C context directly to the child process after clearing stale ObservMe and W3C variables.
|
|
515
|
+
3. The shipped child extension makes only the Pi process environment eligible for lineage; trusted project `.env` remains configuration-only.
|
|
516
|
+
4. The child accepts the envelope only when every required value validates and the W3C and duplicate trace metadata agree.
|
|
517
|
+
5. Invalid envelopes fail open without raw-value diagnostics. Explicit runtime overrides are reserved for controlled embedders and tests.
|
|
518
|
+
|
|
519
|
+
This is process-boundary validation, not a cryptographic launcher signature. A future orchestration extension may add signing if it needs stronger provenance against other code running as the same local user, but it must preserve the current bounded validation and fail-open behavior.
|
|
520
|
+
|
|
521
|
+
### Isolation and safety
|
|
522
|
+
|
|
523
|
+
Tmux isolation does not sandbox filesystem or network access. A tmux child Pi process has the permissions of the user account.
|
|
524
|
+
|
|
525
|
+
Requirements:
|
|
526
|
+
|
|
527
|
+
- confirm project-local agents before running them unless the project is already trusted and policy disables confirmation
|
|
528
|
+
- do not pass secrets through command strings when a safer env/pipe path is available
|
|
529
|
+
- do not log raw env, raw task prompts, raw command lines, or full paths by default
|
|
530
|
+
- support cancellation and timeout for spawned children
|
|
531
|
+
- avoid unbounded local registries, output buffers, and result files
|
|
532
|
+
- clean up temporary files containing prompts or status details
|
|
533
|
+
- fail open for ObservMe export failures, but fail safely for orchestration control errors
|
|
534
|
+
|
|
535
|
+
## 6. Spans and logs required for dashboards
|
|
536
|
+
|
|
537
|
+
### Spans
|
|
538
|
+
|
|
539
|
+
Required span names:
|
|
540
|
+
|
|
541
|
+
```text
|
|
542
|
+
pi.session
|
|
543
|
+
pi.agent.run
|
|
544
|
+
pi.turn
|
|
545
|
+
pi.llm.request
|
|
546
|
+
pi.tool.call
|
|
547
|
+
pi.agent.spawn
|
|
548
|
+
pi.agent.wait
|
|
549
|
+
pi.agent.join
|
|
550
|
+
pi.bash.execution
|
|
551
|
+
pi.compaction
|
|
552
|
+
pi.branch
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Agent/subagent-specific spans:
|
|
556
|
+
|
|
557
|
+
- `pi.agent.run`: one prompt lifecycle in current agent runtime.
|
|
558
|
+
- `pi.agent.spawn`: parent operation that launches a child Pi process.
|
|
559
|
+
- `pi.agent.wait`: parent waiting for child progress/completion.
|
|
560
|
+
- `pi.agent.join`: parent collecting child result/status.
|
|
561
|
+
|
|
562
|
+
### Logs
|
|
563
|
+
|
|
564
|
+
Agent-tree log events expected by Loki dashboards:
|
|
565
|
+
|
|
566
|
+
```text
|
|
567
|
+
agent.run.started
|
|
568
|
+
agent.run.completed
|
|
569
|
+
agent.run.failed
|
|
570
|
+
agent.spawn.started
|
|
571
|
+
agent.spawn.completed
|
|
572
|
+
agent.spawn.failed
|
|
573
|
+
agent.wait.started
|
|
574
|
+
agent.wait.completed
|
|
575
|
+
agent.join.started
|
|
576
|
+
agent.join.completed
|
|
577
|
+
agent.orphaned
|
|
578
|
+
trace_context.propagation_failed
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
Agent-tree logs use:
|
|
582
|
+
|
|
583
|
+
```text
|
|
584
|
+
event.category = agent-tree
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Loki normalizes dotted OTEL names, so Grafana queries use labels such as:
|
|
588
|
+
|
|
589
|
+
```text
|
|
590
|
+
event_name
|
|
591
|
+
pi_agent_id
|
|
592
|
+
pi_agent_parent_id
|
|
593
|
+
pi_agent_root_id
|
|
594
|
+
pi_workflow_id
|
|
595
|
+
pi_agent_spawn_id
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
## 7. Metrics required by the dashboards
|
|
599
|
+
|
|
600
|
+
Prometheus metrics must use only low-cardinality labels.
|
|
601
|
+
|
|
602
|
+
### Agent run metrics
|
|
603
|
+
|
|
604
|
+
```text
|
|
605
|
+
observme_agent_runs_total
|
|
606
|
+
observme_agent_run_errors_total
|
|
607
|
+
observme_agent_run_duration_ms
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Expected labels:
|
|
611
|
+
|
|
612
|
+
```text
|
|
613
|
+
agent_role
|
|
614
|
+
environment
|
|
615
|
+
provider/model only for LLM metrics, not agent-run metrics
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Dashboard examples:
|
|
619
|
+
|
|
620
|
+
```promql
|
|
621
|
+
sum(rate(observme_agent_runs_total[$__rate_interval])) by (agent_role)
|
|
622
|
+
histogram_quantile(0.95, sum(rate(observme_agent_run_duration_ms_bucket[$__rate_interval])) by (agent_role, le))
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### Subagent spawn metrics
|
|
626
|
+
|
|
627
|
+
```text
|
|
628
|
+
observme_subagents_spawned_total
|
|
629
|
+
observme_subagent_spawn_failures_total
|
|
630
|
+
observme_subagent_spawn_duration_ms
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Expected labels:
|
|
634
|
+
|
|
635
|
+
```text
|
|
636
|
+
agent_role
|
|
637
|
+
subagent_depth
|
|
638
|
+
spawn_type
|
|
639
|
+
spawn_reason
|
|
640
|
+
error_class only on failures
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
Dashboard examples:
|
|
644
|
+
|
|
645
|
+
```promql
|
|
646
|
+
sum(rate(observme_subagents_spawned_total[$__rate_interval])) by (subagent_depth, spawn_type, spawn_reason)
|
|
647
|
+
sum(rate(observme_subagent_spawn_failures_total[$__rate_interval])) by (subagent_depth, spawn_type, spawn_reason, error_class)
|
|
648
|
+
histogram_quantile(0.95, sum(rate(observme_subagent_spawn_duration_ms_bucket[$__rate_interval])) by (agent_role, spawn_type, spawn_reason, le))
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
### Agent tree metrics
|
|
652
|
+
|
|
653
|
+
```text
|
|
654
|
+
observme_active_agents
|
|
655
|
+
observme_agent_tree_depth
|
|
656
|
+
observme_agent_tree_width
|
|
657
|
+
observme_agent_fanout_count
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Expected labels:
|
|
661
|
+
|
|
662
|
+
```text
|
|
663
|
+
agent_role
|
|
664
|
+
subagent_depth
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Dashboard examples:
|
|
668
|
+
|
|
669
|
+
```promql
|
|
670
|
+
sum(observme_active_agents) by (agent_role, subagent_depth)
|
|
671
|
+
histogram_quantile(0.95, sum(rate(observme_agent_tree_depth_bucket[$__rate_interval])) by (subagent_depth, le))
|
|
672
|
+
histogram_quantile(0.95, sum(rate(observme_agent_tree_width_bucket[$__rate_interval])) by (subagent_depth, le))
|
|
673
|
+
histogram_quantile(0.95, sum(rate(observme_agent_fanout_count_bucket[$__rate_interval])) by (subagent_depth, le))
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Lineage health metrics
|
|
677
|
+
|
|
678
|
+
```text
|
|
679
|
+
observme_orphan_agents_total
|
|
680
|
+
observme_trace_context_propagation_failures_total
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Expected labels:
|
|
684
|
+
|
|
685
|
+
```text
|
|
686
|
+
agent_role
|
|
687
|
+
subagent_depth
|
|
688
|
+
reason/status as bounded enums
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Dashboard examples:
|
|
692
|
+
|
|
693
|
+
```promql
|
|
694
|
+
sum(rate(observme_orphan_agents_total[$__rate_interval])) by (agent_role, subagent_depth)
|
|
695
|
+
sum(rate(observme_trace_context_propagation_failures_total[$__rate_interval])) by (agent_role, subagent_depth)
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Wait/join and child failure metrics
|
|
699
|
+
|
|
700
|
+
```text
|
|
701
|
+
observme_agent_wait_duration_ms
|
|
702
|
+
observme_agent_join_duration_ms
|
|
703
|
+
observme_child_agent_failures_total
|
|
704
|
+
observme_parent_recovered_from_child_failure_total
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
Expected labels:
|
|
708
|
+
|
|
709
|
+
```text
|
|
710
|
+
agent_role
|
|
711
|
+
subagent_depth
|
|
712
|
+
status/reason as bounded enums when needed
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Dashboard examples:
|
|
716
|
+
|
|
717
|
+
```promql
|
|
718
|
+
histogram_quantile(0.95, sum(rate(observme_agent_wait_duration_ms_bucket[$__rate_interval])) by (agent_role, le))
|
|
719
|
+
histogram_quantile(0.95, sum(rate(observme_agent_join_duration_ms_bucket[$__rate_interval])) by (agent_role, le))
|
|
720
|
+
sum(rate(observme_child_agent_failures_total[$__rate_interval])) by (agent_role, subagent_depth)
|
|
721
|
+
sum(rate(observme_parent_recovered_from_child_failure_total[$__rate_interval])) by (agent_role, subagent_depth)
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
## 8. Labels that are allowed vs forbidden
|
|
725
|
+
|
|
726
|
+
### Allowed metric labels
|
|
727
|
+
|
|
728
|
+
Low-cardinality labels allowed for aggregates:
|
|
729
|
+
|
|
730
|
+
```text
|
|
731
|
+
agent_role
|
|
732
|
+
agent_capability
|
|
733
|
+
subagent_depth
|
|
734
|
+
spawn_type
|
|
735
|
+
spawn_reason
|
|
736
|
+
status
|
|
737
|
+
reason
|
|
738
|
+
error_class
|
|
739
|
+
environment
|
|
740
|
+
provider
|
|
741
|
+
model
|
|
742
|
+
tool_name
|
|
743
|
+
tool_category
|
|
744
|
+
operation
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Forbidden metric labels
|
|
748
|
+
|
|
749
|
+
These may appear on traces/logs, but must not be Prometheus labels:
|
|
750
|
+
|
|
751
|
+
```text
|
|
752
|
+
session_id
|
|
753
|
+
workflow_id
|
|
754
|
+
workflow_root_agent_id
|
|
755
|
+
agent_id
|
|
756
|
+
parent_agent_id
|
|
757
|
+
child_agent_id
|
|
758
|
+
agent_run_id
|
|
759
|
+
spawn_id
|
|
760
|
+
spawn_tool_call_id
|
|
761
|
+
trace_id
|
|
762
|
+
span_id
|
|
763
|
+
entry_id
|
|
764
|
+
tool_call_id
|
|
765
|
+
raw_command
|
|
766
|
+
raw_prompt
|
|
767
|
+
raw_path
|
|
768
|
+
raw_error_message
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
The production Collector config reinforces this by deleting high-cardinality metric resource attributes such as `pi.workflow.id`, `pi.agent.id`, `pi.agent.parent_id`, `pi.agent.root_id`, `pi.agent.spawn.id`, `pi.agent.child.id`, and `pi.session.id` from the metrics pipeline.
|
|
772
|
+
|
|
773
|
+
## 9. What `/obs agents` needs
|
|
774
|
+
|
|
775
|
+
`/obs agents` combines:
|
|
776
|
+
|
|
777
|
+
1. In-memory runtime state from the current Pi process.
|
|
778
|
+
2. Prometheus aggregate queries.
|
|
779
|
+
3. Tempo trace search by safe lineage attributes.
|
|
780
|
+
|
|
781
|
+
It renders:
|
|
782
|
+
|
|
783
|
+
- workflow id and root id
|
|
784
|
+
- current agent id, role, and depth
|
|
785
|
+
- current session id
|
|
786
|
+
- fan-out count in current trace
|
|
787
|
+
- tree depth/width/active/orphan counts
|
|
788
|
+
- recent children
|
|
789
|
+
- wait/join hints
|
|
790
|
+
- aggregate series counts
|
|
791
|
+
- Tempo drill-down attributes and latest trace id
|
|
792
|
+
|
|
793
|
+
Current PromQL used by `/obs agents`:
|
|
794
|
+
|
|
795
|
+
```promql
|
|
796
|
+
sum(rate(observme_subagents_spawned_total[1h])) by (agent_role, subagent_depth, spawn_type, spawn_reason)
|
|
797
|
+
histogram_quantile(0.95, sum(rate(observme_agent_fanout_count_bucket[1h])) by (subagent_depth, le))
|
|
798
|
+
sum(rate(observme_orphan_agents_total[1h])) by (agent_role, subagent_depth)
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
Tempo drill-down uses span attributes:
|
|
802
|
+
|
|
803
|
+
```text
|
|
804
|
+
pi.agent.id
|
|
805
|
+
pi.workflow.id
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
These are query attributes, not metric labels.
|
|
809
|
+
|
|
810
|
+
## 10. Pi subagent example and tmux compatibility
|
|
811
|
+
|
|
812
|
+
The Pi example subagent extension:
|
|
813
|
+
|
|
814
|
+
- registers a `subagent` tool
|
|
815
|
+
- supports single, parallel, and chain modes
|
|
816
|
+
- discovers user agents from `~/.pi/agent/agents/*.md`
|
|
817
|
+
- optionally discovers project agents from `.pi/agents/*.md`
|
|
818
|
+
- spawns child `pi` processes with `child_process.spawn(...)`
|
|
819
|
+
- runs children with `--mode json -p --no-session`
|
|
820
|
+
- reads child JSON events from stdout
|
|
821
|
+
- collects child assistant messages, tool results, token usage, cost, and final output
|
|
822
|
+
- supports Ctrl+C abort by killing child processes
|
|
823
|
+
|
|
824
|
+
By default, the example spawn call does not pass ObservMe propagation env and does not call ObservMe's `startSubagentSpawn` / `completeSubagentSpawn` / `failSubagentSpawn` helpers.
|
|
825
|
+
|
|
826
|
+
Therefore, to use that style of subagent and still populate ObservMe dashboards, an ObservMe-aware adapter must wrap the child process spawn and pass the returned env to the child process.
|
|
827
|
+
|
|
828
|
+
Minimum adapter behavior:
|
|
829
|
+
|
|
830
|
+
1. Before spawning child Pi, call `startSubagentSpawn` with spawn type/reason and safe command metadata.
|
|
831
|
+
2. Pass `started.env` into `child_process.spawn`.
|
|
832
|
+
3. On child process close success, call `completeSubagentSpawn`.
|
|
833
|
+
4. On child process error/abort/failure, call `failSubagentSpawn` or complete with cancelled/failed status.
|
|
834
|
+
5. Around blocking waits, record `pi.agent.wait`.
|
|
835
|
+
6. When child output is collected, record `pi.agent.join` with child status.
|
|
836
|
+
7. Ensure the child command loads ObservMe as an extension/package.
|
|
837
|
+
8. Ensure the child ObservMe runtime accepts the propagated parent context as trusted.
|
|
838
|
+
|
|
839
|
+
Without that adapter, parent tool metrics may show a `subagent` tool call, but the agent-tree dashboard will not have reliable spawn/depth/fan-out/wait/join lineage.
|
|
840
|
+
|
|
841
|
+
### Tmux compatibility conclusion
|
|
842
|
+
|
|
843
|
+
Running subagents in tmux is supported by the requirements, but tmux must be integrated as an ObservMe-aware runner.
|
|
844
|
+
|
|
845
|
+
The correct mental model is:
|
|
846
|
+
|
|
847
|
+
```text
|
|
848
|
+
parent Pi + ObservMe
|
|
849
|
+
-> orchestration extension starts pi.agent.spawn
|
|
850
|
+
-> orchestration extension starts tmux with explicit ObservMe env
|
|
851
|
+
-> child Pi starts inside tmux and loads ObservMe
|
|
852
|
+
-> child ObservMe accepts trusted parent lineage
|
|
853
|
+
-> parent records wait/join based on tmux/process/result status
|
|
854
|
+
-> Grafana correlates parent and child by workflow/agent lineage
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
If the child loads ObservMe but does not receive or trust parent lineage, the child is observable but not connected as a subagent.
|
|
858
|
+
|
|
859
|
+
## 11. Dashboard readiness checklist
|
|
860
|
+
|
|
861
|
+
Use this checklist before expecting subagents to appear correctly in Grafana.
|
|
862
|
+
|
|
863
|
+
### Parent process
|
|
864
|
+
|
|
865
|
+
- [ ] ObservMe extension is loaded in the parent Pi process.
|
|
866
|
+
- [ ] Parent has emitted `session_start`.
|
|
867
|
+
- [ ] Parent has a current `pi.workflow.id` and `pi.agent.id`.
|
|
868
|
+
- [ ] `workflow.enabled=true`.
|
|
869
|
+
- [ ] `agent.propagateToSubagents=true`.
|
|
870
|
+
- [ ] Parent subagent launcher uses ObservMe spawn helpers.
|
|
871
|
+
- [ ] Parent passes returned env into the child Pi process.
|
|
872
|
+
- [ ] In tmux mode, parent injects env explicitly into the tmux child command and does not rely on stale tmux server env.
|
|
873
|
+
- [ ] Parent records tmux session/pane status in a bounded local registry.
|
|
874
|
+
- [ ] Parent records spawn completion/failure.
|
|
875
|
+
- [ ] Parent records wait/join if it waits for child output, process exit, status marker, or operator action.
|
|
876
|
+
|
|
877
|
+
### Child process
|
|
878
|
+
|
|
879
|
+
- [ ] Child Pi process loads ObservMe.
|
|
880
|
+
- [ ] Child command does not use `--no-extensions` unless ObservMe is explicitly re-added.
|
|
881
|
+
- [ ] Child receives `OBSERVME_WORKFLOW_ID`, `OBSERVME_PARENT_AGENT_ID`, `OBSERVME_ROOT_AGENT_ID`, `OBSERVME_AGENT_DEPTH`, and `OBSERVME_SPAWN_ID`.
|
|
882
|
+
- [ ] Child receives `traceparent` when trace propagation is enabled and possible.
|
|
883
|
+
- [ ] Child accepts propagated ObservMe env as trusted parent context.
|
|
884
|
+
- [ ] Child exports OTLP to the configured Collector/backend.
|
|
885
|
+
- [ ] In tmux-interactive mode, operators can attach/detach without changing lineage or losing telemetry.
|
|
886
|
+
|
|
887
|
+
### Collector/backend
|
|
888
|
+
|
|
889
|
+
- [ ] Traces pipeline preserves `pi.workflow.*` and `pi.agent.*` attributes.
|
|
890
|
+
- [ ] Logs pipeline preserves normalized event labels/metadata needed by Loki dashboards.
|
|
891
|
+
- [ ] Metrics pipeline drops high-cardinality lineage attributes but preserves safe labels.
|
|
892
|
+
- [ ] Prometheus contains `observme_subagents_spawned_total` after a subagent run.
|
|
893
|
+
- [ ] Loki contains `event_category="agent-tree"` logs.
|
|
894
|
+
- [ ] Tempo can search by `pi.workflow.id` or `pi.agent.id`.
|
|
895
|
+
|
|
896
|
+
### Quick checks
|
|
897
|
+
|
|
898
|
+
Prometheus:
|
|
899
|
+
|
|
900
|
+
```promql
|
|
901
|
+
sum(rate(observme_subagents_spawned_total[5m])) by (agent_role, subagent_depth, spawn_type, spawn_reason)
|
|
902
|
+
sum(rate(observme_orphan_agents_total[5m])) by (agent_role, subagent_depth)
|
|
903
|
+
sum(rate(observme_trace_context_propagation_failures_total[5m])) by (agent_role, subagent_depth)
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
Loki:
|
|
907
|
+
|
|
908
|
+
```logql
|
|
909
|
+
{service_name="observme-pi-extension", event_category="agent-tree"}
|
|
910
|
+
{service_name="observme-pi-extension", event_name="agent.spawn.completed"}
|
|
911
|
+
{service_name="observme-pi-extension", event_name="agent.orphaned"}
|
|
912
|
+
{service_name="observme-pi-extension", event_name="trace_context.propagation_failed"}
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
Pi command:
|
|
916
|
+
|
|
917
|
+
```text
|
|
918
|
+
/obs agents
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### Dashboard navigation note
|
|
922
|
+
|
|
923
|
+
Use the improved dashboards in this order when validating a root-agent/subagent scenario:
|
|
924
|
+
|
|
925
|
+
1. Start in **ObservMe Overview** and confirm the `Agent lineage` and `Health` rows are green or intentionally idle.
|
|
926
|
+
2. Open **Trace Journey** with the same time range and apply Loki/Tempo-only `session_id`, `workflow_id`, `agent_id`, or `agent_run_id` filters to follow one execution.
|
|
927
|
+
3. Open **Agents and Subagents** for spawn failure, orphan, propagation, child recovery, wait/join, fan-out, and depth ratios, then use the handoff rows to jump back to Trace Journey or Tempo.
|
|
928
|
+
4. Open **Agent Node Graphs** only for aggregate topology; it shows selected-range counts and red health nodes/edges, not a single trace tree.
|
|
929
|
+
5. Open **SLO Health** or **Export Health** when lineage panels look empty or stale, because healthy idle ranges, missing optional child telemetry, and export failures have different meanings.
|
|
930
|
+
|
|
931
|
+
High-cardinality identifiers remain log/trace filters only. Prometheus panels should continue to use bounded labels such as `agent_role`, `subagent_depth`, `spawn_type`, `spawn_reason`, `status`, `reason`, and `error_class`.
|
|
932
|
+
|
|
933
|
+
### Dashboard implementation note
|
|
934
|
+
|
|
935
|
+
The Agents and Agent Node Graphs dashboards now surface the main operator questions directly: spawn failure ratio, orphan pressure, trace-context propagation failure ratio, child recovery ratio, depth/fan-out alert references, slow/failing/orphan/high-fan-out top tables, and Loki handoff rows with Trace Journey/Tempo drill-down links. The node graphs also include red health nodes/edges for failed spawns, orphan lineage, and propagation failures alongside selected-range counts.
|
|
936
|
+
|
|
937
|
+
`agent_capability` remains deliberately absent from dashboard filters until a launcher emits a bounded capability label consistently. Keep capability detail in Loki/Tempo or orchestration-local state unless the launcher maps names into a documented low-cardinality enum.
|
|
938
|
+
|
|
939
|
+
## 12. Current implementation checkpoints and gaps
|
|
940
|
+
|
|
941
|
+
These checkpoints reflect the current code and dashboards after source-review remediation.
|
|
942
|
+
|
|
943
|
+
### Present pieces
|
|
944
|
+
|
|
945
|
+
- Agent lineage generation and complete propagated-envelope validation exist in `src/pi/agent-lineage.ts`.
|
|
946
|
+
- The production extension enables process-environment lineage eligibility while keeping trusted project `.env` outside the provenance boundary.
|
|
947
|
+
- Valid W3C context explicitly parents the child `pi.session`; unavailable continuation uses a validated span link or bounded propagation-failure fallback.
|
|
948
|
+
- Bounded agent-tree tracking exists in `src/pi/agent-tree-tracker.ts`.
|
|
949
|
+
- Spawn/wait/join helper functions exist in `src/pi/subagent-spawn.ts`.
|
|
950
|
+
- Spawn duration is recorded on completion and launcher failure. Child completion/join records child failure and confirmed parent recovery once through bounded deduplication state.
|
|
951
|
+
- Session, agent-run/turn, LLM, tool/bash, and session metadata/tree handlers are split under `src/pi/event-handlers/` behind the stable `src/pi/handlers.ts` facade.
|
|
952
|
+
- Root workflow duration is recorded at shutdown, and failed agent runs increment `observme_agent_run_errors_total`.
|
|
953
|
+
- `/obs agents` is implemented and uses local runtime state, Prometheus aggregates, and Tempo drill-down attributes.
|
|
954
|
+
- Grafana dashboards include agent/subagent panels and alert/SLO rules.
|
|
955
|
+
- Tests cover child trace parenting, sanitized propagation fallback, spawn duration, child failure/recovery deduplication, wait/join spans, and low-cardinality metric labels.
|
|
956
|
+
|
|
957
|
+
### Remaining integration gaps before relying on full subagent dashboards
|
|
958
|
+
|
|
959
|
+
1. **External and tmux subagent launchers are not automatically wrapped.**
|
|
960
|
+
- `src/pi/subagent-spawn.ts` exposes helpers, but arbitrary extensions that call `child_process.spawn` or `tmux new-session` will not be detected automatically.
|
|
961
|
+
- The Pi example subagent extension currently spawns child Pi processes without ObservMe env propagation.
|
|
962
|
+
- A future tmux orchestration extension must own this wrapping and lifecycle tracking.
|
|
963
|
+
|
|
964
|
+
2. **Some dashboard label expectations remain broader than current emitted labels.**
|
|
965
|
+
- `observme_active_agents` currently carries `environment` and `agent_role`, not `subagent_depth`.
|
|
966
|
+
- `observme_subagent_spawn_failures_total` carries `spawn_type` and `error_class`, while some dashboard queries also group by depth/reason.
|
|
967
|
+
- Orphan signals emitted by tracker and session-propagation paths do not yet share one identical label set.
|
|
968
|
+
- These missing dimensions do not introduce high cardinality, but affected grouped panels may show blank label values until the metric contract is aligned.
|
|
969
|
+
|
|
970
|
+
3. **Agent capability is not automatically derived from Pi markdown agent definitions.**
|
|
971
|
+
- If dashboards should show `agent_capability`, the subagent launcher must map agent names/capabilities into a documented bounded enum before metrics use them.
|
|
972
|
+
|
|
973
|
+
4. **Tmux management state does not exist yet.**
|
|
974
|
+
- ObservMe has bounded in-memory telemetry agent-tree state, but not a tmux orchestration registry for session names, panes, attach commands, stop/cleanup state, or result collection.
|
|
975
|
+
- A future extension must add that management layer while keeping telemetry privacy and cardinality boundaries intact.
|
|
976
|
+
|
|
977
|
+
## 13. Decision summary
|
|
978
|
+
|
|
979
|
+
To use subagents and have them appear in ObservMe dashboards, the extension must treat subagent support as explicit instrumentation, not passive observation.
|
|
980
|
+
|
|
981
|
+
Required decisions:
|
|
982
|
+
|
|
983
|
+
1. **Subagent spawn point:** choose the exact launcher(s) to wrap, including tmux session creation and any direct `child_process.spawn` paths.
|
|
984
|
+
2. **Tmux control model:** decide supported modes (`tmux-interactive`, `tmux-print-json`, `tmux-rpc`), session naming, attach/detach behavior, status detection, and cleanup policy.
|
|
985
|
+
3. **Trust model:** use the implemented complete process-envelope boundary; decide whether a future orchestrator also needs cryptographic signing against same-user processes.
|
|
986
|
+
4. **Child ObservMe loading:** decide whether child Pi commands rely on installed ObservMe packages or receive explicit `-e` extension loading.
|
|
987
|
+
5. **Capability mapping:** decide whether Pi markdown agent names map to `agent_capability`, `agent_role`, both, or neither.
|
|
988
|
+
6. **Metric label contract:** align the remaining active-agent, spawn-failure, and orphan dashboard dimensions while keeping high-cardinality ids out of labels.
|
|
989
|
+
7. **Duration/failure accounting:** use the implemented elapsed spawn duration and deduplicated child failure/recovery counters at completion/join transitions.
|
|
990
|
+
8. **Packaging:** ensure both parent and child Pi processes load ObservMe and share compatible config/export endpoints.
|
|
991
|
+
9. **Management command surface:** define commands/tools for list, start, status, attach, send, wait, join, stop, and cleanup.
|
|
992
|
+
|
|
993
|
+
Once those decisions are implemented, root agents and subagents can be distinguished as follows:
|
|
994
|
+
|
|
995
|
+
- Root agent: no parent id, depth `0`, role `root` or `orchestrator`.
|
|
996
|
+
- Subagent: has parent id, inherited workflow/root id, depth `1+`, role `subagent` or a bounded worker role.
|
|
997
|
+
- Orphan: has incomplete/broken parent lineage or parent cannot be linked, with orphan logs/metrics emitted.
|