forge-lens-fl 0.2.0__tar.gz
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.
- forge_lens_fl-0.2.0/LICENSE +21 -0
- forge_lens_fl-0.2.0/PKG-INFO +106 -0
- forge_lens_fl-0.2.0/README.md +80 -0
- forge_lens_fl-0.2.0/pyproject.toml +156 -0
- forge_lens_fl-0.2.0/pyproject.toml.orig +117 -0
- forge_lens_fl-0.2.0/src/forge_lens/__init__.py +3 -0
- forge_lens_fl-0.2.0/src/forge_lens/__main__.py +3 -0
- forge_lens_fl-0.2.0/src/forge_lens/adapters/__init__.py +5 -0
- forge_lens_fl-0.2.0/src/forge_lens/adapters/capabilities.py +70 -0
- forge_lens_fl-0.2.0/src/forge_lens/adapters/claude_code.py +210 -0
- forge_lens_fl-0.2.0/src/forge_lens/api/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/api/app.py +2003 -0
- forge_lens_fl-0.2.0/src/forge_lens/api/clock.py +18 -0
- forge_lens_fl-0.2.0/src/forge_lens/cli/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/cli/main.py +2620 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/__init__.py +55 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/base.py +16 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/jsonschema.py +74 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/provenance.py +28 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/__init__.py +58 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/agent.py +58 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/dataset.py +54 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/evaluation.py +33 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/evidence.py +52 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/experiment.py +70 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/refs.py +48 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/trace.py +149 -0
- forge_lens_fl-0.2.0/src/forge_lens/contracts/v1/usage.py +71 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/bounded.py +42 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/config.py +208 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/errors.py +35 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/hashing.py +21 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/ids.py +73 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/jsonutil.py +45 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/metrics.py +86 -0
- forge_lens_fl-0.2.0/src/forge_lens/core/time.py +60 -0
- forge_lens_fl-0.2.0/src/forge_lens/eval/__init__.py +19 -0
- forge_lens_fl-0.2.0/src/forge_lens/eval/compare.py +355 -0
- forge_lens_fl-0.2.0/src/forge_lens/eval/evaluators.py +1229 -0
- forge_lens_fl-0.2.0/src/forge_lens/eval/runner.py +76 -0
- forge_lens_fl-0.2.0/src/forge_lens/graph/__init__.py +24 -0
- forge_lens_fl-0.2.0/src/forge_lens/graph/algorithms.py +147 -0
- forge_lens_fl-0.2.0/src/forge_lens/graph/builder.py +203 -0
- forge_lens_fl-0.2.0/src/forge_lens/graph/models.py +62 -0
- forge_lens_fl-0.2.0/src/forge_lens/ingest/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/ingest/pipeline.py +326 -0
- forge_lens_fl-0.2.0/src/forge_lens/install/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/install/guided.py +171 -0
- forge_lens_fl-0.2.0/src/forge_lens/install/lifecycle.py +133 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/__init__.py +21 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/correlation.py +776 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/cost.py +123 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/efficiency.py +74 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/graph_intel.py +54 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/pricing.py +180 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/recommendations.py +75 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/regressions.py +61 -0
- forge_lens_fl-0.2.0/src/forge_lens/intel/waste.py +180 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/__init__.py +35 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/bundle.py +47 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/classify.py +629 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/eval_suggest.py +364 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/hypothesis.py +419 -0
- forge_lens_fl-0.2.0/src/forge_lens/investigate/replay.py +83 -0
- forge_lens_fl-0.2.0/src/forge_lens/mcp_server.py +456 -0
- forge_lens_fl-0.2.0/src/forge_lens/ops/__init__.py +29 -0
- forge_lens_fl-0.2.0/src/forge_lens/ops/agents.py +189 -0
- forge_lens_fl-0.2.0/src/forge_lens/ops/alerts.py +394 -0
- forge_lens_fl-0.2.0/src/forge_lens/ops/loops.py +113 -0
- forge_lens_fl-0.2.0/src/forge_lens/otlp/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/otlp/normalize.py +398 -0
- forge_lens_fl-0.2.0/src/forge_lens/otlp/openinference.py +161 -0
- forge_lens_fl-0.2.0/src/forge_lens/sanitize/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/sanitize/redact.py +426 -0
- forge_lens_fl-0.2.0/src/forge_lens/sdk/__init__.py +18 -0
- forge_lens_fl-0.2.0/src/forge_lens/sdk/context.py +56 -0
- forge_lens_fl-0.2.0/src/forge_lens/sdk/exporter.py +97 -0
- forge_lens_fl-0.2.0/src/forge_lens/sdk/query.py +621 -0
- forge_lens_fl-0.2.0/src/forge_lens/sdk/tracer.py +635 -0
- forge_lens_fl-0.2.0/src/forge_lens/security/__init__.py +27 -0
- forge_lens_fl-0.2.0/src/forge_lens/security/keys.py +58 -0
- forge_lens_fl-0.2.0/src/forge_lens/security/mcp_inspect.py +122 -0
- forge_lens_fl-0.2.0/src/forge_lens/storage/__init__.py +1 -0
- forge_lens_fl-0.2.0/src/forge_lens/storage/base.py +233 -0
- forge_lens_fl-0.2.0/src/forge_lens/storage/sqlite.py +2082 -0
- forge_lens_fl-0.2.0/src/forge_lens/ui/__init__.py +29 -0
- forge_lens_fl-0.2.0/src/forge_lens/ui/i18n.py +143 -0
- forge_lens_fl-0.2.0/src/forge_lens/ui/kit.py +689 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Edgar Sócrates Caria
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: forge-lens-fl
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Local-first, open-source agentic observability: traces, tools, tokens, cost and evidence.
|
|
5
|
+
Keywords: observability,opentelemetry,openinference,agents,llm,tracing
|
|
6
|
+
Author: Edgar Sócrates Caria
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Dist: pydantic>=2.7
|
|
17
|
+
Requires-Dist: typer>=0.12
|
|
18
|
+
Requires-Dist: rich>=13.7
|
|
19
|
+
Requires-Dist: fastapi>=0.115 ; extra == 'server'
|
|
20
|
+
Requires-Dist: uvicorn>=0.30 ; extra == 'server'
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Project-URL: Repository, https://github.com/EdgarSocrates98/forge-lens
|
|
23
|
+
Project-URL: Issues, https://github.com/EdgarSocrates98/forge-lens/issues
|
|
24
|
+
Provides-Extra: server
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Forge Lens
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="docs/assets/logo.png" alt="Forge Lens logo" width="420" />
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
**Local-first, open-source agentic observability.** Understand every agent execution. Trace every tool. Measure every cost. Investigate every failure. Prove every improvement.
|
|
34
|
+
|
|
35
|
+
Forge Lens receives, persists and explains agent executions — via OTLP/HTTP, OpenInference attributes, or its own SDKs — on your machine, with no mandatory external dependency.
|
|
36
|
+
|
|
37
|
+
## Status
|
|
38
|
+
|
|
39
|
+
Cycles 00–01 (foundation, verified): contracts v1, OTLP/HTTP JSON ingestion, sanitization, SQLite WAL store, Python + TypeScript SDKs, CLI.
|
|
40
|
+
Cycles 03–06 backend: temporal execution graph (`/v1/graph/*`), token/cost intelligence (`/v1/traces/{id}/cost`), failure classification + recorded replay + incident bundles (`/v1/traces/{id}/failure|replay|incident`), deterministic evaluation (`/v1/eval/*`), versioned datasets + regression gates — reports in `docs/cycles/`.
|
|
41
|
+
Cycle 02: Angular Studio (`apps/studio`) — Trace Explorer with sortable/filterable list, waterfall with span detail, an evidence pane (cost/failure/loops/graph-analysis payloads rendered as JSON, plus eval results and recorded replay in tables), ops summary view, host-capability table, dark/light themes, URL-state sync, lazy routes, typed API client.
|
|
42
|
+
Cycle 07: loop/no-progress detection (`/v1/traces/{id}/loops`), bounded specialist runtime (`/v1/analyze/*`), threshold alerts (`/v1/alerts/evaluate`), ops summary (`/v1/ops/summary`), MCP security observer (`/v1/traces/{id}/security`).
|
|
43
|
+
Cycle 08: auth modes (`none|key|keys`) with API keys + roles + per-project tenancy, audit trail (`/v1/admin/audit`), retention (`forge-lens prune|archive`, `/v1/admin/prune`), TLS passthrough on `serve`.
|
|
44
|
+
Cycle 09: SSE replay (`/v1/traces/{id}/stream`), measured benchmarks at 1k/10k/100k spans (`scripts/benchmark.py` → `docs/benchmarks/`), archive-before-delete lifecycle.
|
|
45
|
+
Cycle 10: honest host-capability matrix (`/v1/capabilities`), Claude Code JSONL importer (`import-claude`), MCP stdio observer (`mcp-serve`), install lifecycle receipts (`install-status`), 7 skills in `skills/`.
|
|
46
|
+
Cycle 11: CycloneDX SBOM generator (`scripts/gen_sbom.py`), release workflow with OIDC trusted publishing + version gate, `CHANGELOG.md`, `docs/versioning.md`, Studio CI job.
|
|
47
|
+
Cycle 12: efficiency intelligence (`/v1/intel/efficiency`, `/v1/traces/{id}/efficiency`), cohort regression (`/v1/intel/regress`), candidate recommendations (`/v1/traces/{id}/recommendations`), graph centrality/concentration analysis (`/v1/graph/traces/{id}/analysis`).
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
Portable install (same model as the other Forge projects — venv under
|
|
52
|
+
`~/.forge/installs/forge-lens`, launcher on PATH, no project-venv
|
|
53
|
+
touch):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
./install.sh # POSIX; . .\install.ps1 on PowerShell
|
|
57
|
+
forge-lens init .
|
|
58
|
+
forge-lens serve # API on http://127.0.0.1:7777
|
|
59
|
+
forge-lens doctor
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Dev checkout alternative: `uv sync --extra server && uv run forge-lens ...`.
|
|
63
|
+
|
|
64
|
+
Instrument an agent:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from forge_lens.sdk import LensTracer
|
|
68
|
+
from forge_lens.sdk.exporter import HTTPExporter
|
|
69
|
+
|
|
70
|
+
tracer = LensTracer(
|
|
71
|
+
service_name="my-agent",
|
|
72
|
+
exporter=HTTPExporter("http://127.0.0.1:7777"),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
with tracer.agent("researcher"):
|
|
76
|
+
with tracer.llm_call("claude-sonnet-4", provider="anthropic") as s:
|
|
77
|
+
tracer.record_usage(s, input_tokens=200, output_tokens=80, total_tokens=280)
|
|
78
|
+
with tracer.tool_call("web_search"):
|
|
79
|
+
... # call the tool
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Inspect:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
forge-lens traces list
|
|
86
|
+
forge-lens traces show <trace-id>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
A runnable offline demo (SDK → pipeline → store → read-back, no server):
|
|
90
|
+
`uv run python examples/quickstart.py`
|
|
91
|
+
|
|
92
|
+
## Principles
|
|
93
|
+
|
|
94
|
+
- **Local-first** — SQLite WAL by default; works fully offline.
|
|
95
|
+
- **Evidence-first** — every claim carries provenance (`observed` / `imported` / `derived` / `inferred` / `unknown`). Inferred never silently becomes observed.
|
|
96
|
+
- **Safe by default** — `capture=metadata` redacts secrets and drops prompt bodies unless you opt into `full`.
|
|
97
|
+
- **OTel/OpenInference compatible** — OTLP/HTTP JSON ingest, `openinference.*` attribute mapping, W3C traceparent propagation.
|
|
98
|
+
|
|
99
|
+
## Documentation
|
|
100
|
+
|
|
101
|
+
See `docs/` — architecture, guides, API/CLI/contracts reference, ADRs and cycle reports (PT-BR first, EN planned).
|
|
102
|
+
|
|
103
|
+
- `docs/guides/quickstart.md` — first trace in minutes
|
|
104
|
+
- `docs/guides/operations-runbook.md` — serve, auth modes, retention, backups, monitoring, alert rules
|
|
105
|
+
- `docs/guides/troubleshooting.md` — symptom → cause → fix
|
|
106
|
+
- `docs/guides/failure-investigation.md` — failure taxonomy (§05.3), root-cause hypotheses (§05.4), eval suggestions (§12.7)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Forge Lens
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/assets/logo.png" alt="Forge Lens logo" width="420" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
**Local-first, open-source agentic observability.** Understand every agent execution. Trace every tool. Measure every cost. Investigate every failure. Prove every improvement.
|
|
8
|
+
|
|
9
|
+
Forge Lens receives, persists and explains agent executions — via OTLP/HTTP, OpenInference attributes, or its own SDKs — on your machine, with no mandatory external dependency.
|
|
10
|
+
|
|
11
|
+
## Status
|
|
12
|
+
|
|
13
|
+
Cycles 00–01 (foundation, verified): contracts v1, OTLP/HTTP JSON ingestion, sanitization, SQLite WAL store, Python + TypeScript SDKs, CLI.
|
|
14
|
+
Cycles 03–06 backend: temporal execution graph (`/v1/graph/*`), token/cost intelligence (`/v1/traces/{id}/cost`), failure classification + recorded replay + incident bundles (`/v1/traces/{id}/failure|replay|incident`), deterministic evaluation (`/v1/eval/*`), versioned datasets + regression gates — reports in `docs/cycles/`.
|
|
15
|
+
Cycle 02: Angular Studio (`apps/studio`) — Trace Explorer with sortable/filterable list, waterfall with span detail, an evidence pane (cost/failure/loops/graph-analysis payloads rendered as JSON, plus eval results and recorded replay in tables), ops summary view, host-capability table, dark/light themes, URL-state sync, lazy routes, typed API client.
|
|
16
|
+
Cycle 07: loop/no-progress detection (`/v1/traces/{id}/loops`), bounded specialist runtime (`/v1/analyze/*`), threshold alerts (`/v1/alerts/evaluate`), ops summary (`/v1/ops/summary`), MCP security observer (`/v1/traces/{id}/security`).
|
|
17
|
+
Cycle 08: auth modes (`none|key|keys`) with API keys + roles + per-project tenancy, audit trail (`/v1/admin/audit`), retention (`forge-lens prune|archive`, `/v1/admin/prune`), TLS passthrough on `serve`.
|
|
18
|
+
Cycle 09: SSE replay (`/v1/traces/{id}/stream`), measured benchmarks at 1k/10k/100k spans (`scripts/benchmark.py` → `docs/benchmarks/`), archive-before-delete lifecycle.
|
|
19
|
+
Cycle 10: honest host-capability matrix (`/v1/capabilities`), Claude Code JSONL importer (`import-claude`), MCP stdio observer (`mcp-serve`), install lifecycle receipts (`install-status`), 7 skills in `skills/`.
|
|
20
|
+
Cycle 11: CycloneDX SBOM generator (`scripts/gen_sbom.py`), release workflow with OIDC trusted publishing + version gate, `CHANGELOG.md`, `docs/versioning.md`, Studio CI job.
|
|
21
|
+
Cycle 12: efficiency intelligence (`/v1/intel/efficiency`, `/v1/traces/{id}/efficiency`), cohort regression (`/v1/intel/regress`), candidate recommendations (`/v1/traces/{id}/recommendations`), graph centrality/concentration analysis (`/v1/graph/traces/{id}/analysis`).
|
|
22
|
+
|
|
23
|
+
## Quickstart
|
|
24
|
+
|
|
25
|
+
Portable install (same model as the other Forge projects — venv under
|
|
26
|
+
`~/.forge/installs/forge-lens`, launcher on PATH, no project-venv
|
|
27
|
+
touch):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
./install.sh # POSIX; . .\install.ps1 on PowerShell
|
|
31
|
+
forge-lens init .
|
|
32
|
+
forge-lens serve # API on http://127.0.0.1:7777
|
|
33
|
+
forge-lens doctor
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Dev checkout alternative: `uv sync --extra server && uv run forge-lens ...`.
|
|
37
|
+
|
|
38
|
+
Instrument an agent:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from forge_lens.sdk import LensTracer
|
|
42
|
+
from forge_lens.sdk.exporter import HTTPExporter
|
|
43
|
+
|
|
44
|
+
tracer = LensTracer(
|
|
45
|
+
service_name="my-agent",
|
|
46
|
+
exporter=HTTPExporter("http://127.0.0.1:7777"),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
with tracer.agent("researcher"):
|
|
50
|
+
with tracer.llm_call("claude-sonnet-4", provider="anthropic") as s:
|
|
51
|
+
tracer.record_usage(s, input_tokens=200, output_tokens=80, total_tokens=280)
|
|
52
|
+
with tracer.tool_call("web_search"):
|
|
53
|
+
... # call the tool
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Inspect:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
forge-lens traces list
|
|
60
|
+
forge-lens traces show <trace-id>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A runnable offline demo (SDK → pipeline → store → read-back, no server):
|
|
64
|
+
`uv run python examples/quickstart.py`
|
|
65
|
+
|
|
66
|
+
## Principles
|
|
67
|
+
|
|
68
|
+
- **Local-first** — SQLite WAL by default; works fully offline.
|
|
69
|
+
- **Evidence-first** — every claim carries provenance (`observed` / `imported` / `derived` / `inferred` / `unknown`). Inferred never silently becomes observed.
|
|
70
|
+
- **Safe by default** — `capture=metadata` redacts secrets and drops prompt bodies unless you opt into `full`.
|
|
71
|
+
- **OTel/OpenInference compatible** — OTLP/HTTP JSON ingest, `openinference.*` attribute mapping, W3C traceparent propagation.
|
|
72
|
+
|
|
73
|
+
## Documentation
|
|
74
|
+
|
|
75
|
+
See `docs/` — architecture, guides, API/CLI/contracts reference, ADRs and cycle reports (PT-BR first, EN planned).
|
|
76
|
+
|
|
77
|
+
- `docs/guides/quickstart.md` — first trace in minutes
|
|
78
|
+
- `docs/guides/operations-runbook.md` — serve, auth modes, retention, backups, monitoring, alert rules
|
|
79
|
+
- `docs/guides/troubleshooting.md` — symptom → cause → fix
|
|
80
|
+
- `docs/guides/failure-investigation.md` — failure taxonomy (§05.3), root-cause hypotheses (§05.4), eval suggestions (§12.7)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "forge-lens-fl"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Local-first, open-source agentic observability: traces, tools, tokens, cost and evidence."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"Programming Language :: Python :: 3.11",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
|
+
"Programming Language :: Python :: 3.14",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
keywords = [
|
|
19
|
+
"observability",
|
|
20
|
+
"opentelemetry",
|
|
21
|
+
"openinference",
|
|
22
|
+
"agents",
|
|
23
|
+
"llm",
|
|
24
|
+
"tracing",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"pydantic>=2.7",
|
|
28
|
+
"typer>=0.12",
|
|
29
|
+
"rich>=13.7",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[project.authors]]
|
|
33
|
+
name = "Edgar Sócrates Caria"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
server = [
|
|
37
|
+
"fastapi>=0.115",
|
|
38
|
+
"uvicorn>=0.30",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Repository = "https://github.com/EdgarSocrates98/forge-lens"
|
|
43
|
+
Issues = "https://github.com/EdgarSocrates98/forge-lens/issues"
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
forge-lens = "forge_lens.cli.main:main"
|
|
47
|
+
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
lint = ["ruff>=0.8"]
|
|
50
|
+
test = [
|
|
51
|
+
"pytest>=8.0",
|
|
52
|
+
"pytest-cov>=6.0",
|
|
53
|
+
"httpx>=0.27",
|
|
54
|
+
]
|
|
55
|
+
types = ["mypy>=1.13"]
|
|
56
|
+
audit = ["pip-audit>=2.7"]
|
|
57
|
+
|
|
58
|
+
[[dependency-groups.dev]]
|
|
59
|
+
include-group = "lint"
|
|
60
|
+
|
|
61
|
+
[[dependency-groups.dev]]
|
|
62
|
+
include-group = "test"
|
|
63
|
+
|
|
64
|
+
[[dependency-groups.dev]]
|
|
65
|
+
include-group = "types"
|
|
66
|
+
|
|
67
|
+
[[dependency-groups.dev]]
|
|
68
|
+
include-group = "audit"
|
|
69
|
+
|
|
70
|
+
[build-system]
|
|
71
|
+
requires = ["uv_build>=0.8.0,<0.13"]
|
|
72
|
+
build-backend = "uv_build"
|
|
73
|
+
|
|
74
|
+
[tool.uv.build-backend]
|
|
75
|
+
module-name = "forge_lens"
|
|
76
|
+
|
|
77
|
+
[tool.ruff]
|
|
78
|
+
line-length = 100
|
|
79
|
+
target-version = "py311"
|
|
80
|
+
src = [
|
|
81
|
+
"src",
|
|
82
|
+
"tests",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint]
|
|
86
|
+
select = [
|
|
87
|
+
"E",
|
|
88
|
+
"F",
|
|
89
|
+
"W",
|
|
90
|
+
"I",
|
|
91
|
+
"UP",
|
|
92
|
+
"B",
|
|
93
|
+
"SIM",
|
|
94
|
+
"C4",
|
|
95
|
+
"RUF",
|
|
96
|
+
"S",
|
|
97
|
+
"DTZ",
|
|
98
|
+
"PT",
|
|
99
|
+
"PTH",
|
|
100
|
+
"TID",
|
|
101
|
+
]
|
|
102
|
+
ignore = ["S608"]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.per-file-ignores]
|
|
105
|
+
"scripts/forge_bootstrap.py" = ["ALL"]
|
|
106
|
+
"scripts/lab/forge_lens_lab.py" = ["S314"]
|
|
107
|
+
"tests/**" = [
|
|
108
|
+
"S101",
|
|
109
|
+
"PT011",
|
|
110
|
+
"PTH",
|
|
111
|
+
"S105",
|
|
112
|
+
"S106",
|
|
113
|
+
]
|
|
114
|
+
"examples/**" = [
|
|
115
|
+
"S101",
|
|
116
|
+
"T201",
|
|
117
|
+
]
|
|
118
|
+
"homolog/**" = [
|
|
119
|
+
"S101",
|
|
120
|
+
"S105",
|
|
121
|
+
"S310",
|
|
122
|
+
"S603",
|
|
123
|
+
"PTH",
|
|
124
|
+
]
|
|
125
|
+
"src/forge_lens/cli/**" = ["T201"]
|
|
126
|
+
"src/forge_lens/ui/**/*.py" = ["ALL"]
|
|
127
|
+
|
|
128
|
+
[tool.pytest.ini_options]
|
|
129
|
+
testpaths = ["tests"]
|
|
130
|
+
addopts = "-q"
|
|
131
|
+
markers = [
|
|
132
|
+
"e2e: end-to-end scenarios",
|
|
133
|
+
"contract: contract and schema tests",
|
|
134
|
+
"benchmark: benchmark smoke tests (tests/bench)",
|
|
135
|
+
"network: legitimately opens sockets (exempt from the offline gate)",
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
[tool.coverage.run]
|
|
139
|
+
source = ["src/forge_lens"]
|
|
140
|
+
omit = ["tests/*"]
|
|
141
|
+
|
|
142
|
+
[tool.coverage.report]
|
|
143
|
+
show_missing = true
|
|
144
|
+
exclude_also = [
|
|
145
|
+
"if TYPE_CHECKING:",
|
|
146
|
+
"raise NotImplementedError",
|
|
147
|
+
"@overload",
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
[tool.mypy]
|
|
151
|
+
python_version = "3.11"
|
|
152
|
+
mypy_path = "src"
|
|
153
|
+
packages = ["forge_lens"]
|
|
154
|
+
strict = true
|
|
155
|
+
warn_unreachable = true
|
|
156
|
+
exclude = ["forge_lens.ui"]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "forge-lens-fl"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Local-first, open-source agentic observability: traces, tools, tokens, cost and evidence."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
authors = [{ name = "Edgar Sócrates Caria" }]
|
|
8
|
+
license = "MIT"
|
|
9
|
+
license-files = ["LICENSE"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Programming Language :: Python :: 3.11",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Programming Language :: Python :: 3.13",
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
keywords = ["observability", "opentelemetry", "openinference", "agents", "llm", "tracing"]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"pydantic>=2.7",
|
|
22
|
+
"typer>=0.12",
|
|
23
|
+
"rich>=13.7",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
server = [
|
|
28
|
+
"fastapi>=0.115",
|
|
29
|
+
"uvicorn>=0.30",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Repository = "https://github.com/EdgarSocrates98/forge-lens"
|
|
34
|
+
Issues = "https://github.com/EdgarSocrates98/forge-lens/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
# Route the installed command through the small dispatcher so a bare
|
|
38
|
+
# `forge-lens install` gets the guided wizard on a real TTY. Pointing the
|
|
39
|
+
# entry point directly at the Typer object bypasses that contract in wheels.
|
|
40
|
+
forge-lens = "forge_lens.cli.main:main"
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
{ include-group = "lint" },
|
|
45
|
+
{ include-group = "test" },
|
|
46
|
+
{ include-group = "types" },
|
|
47
|
+
{ include-group = "audit" },
|
|
48
|
+
]
|
|
49
|
+
lint = ["ruff>=0.8"]
|
|
50
|
+
test = [
|
|
51
|
+
"pytest>=8.0",
|
|
52
|
+
"pytest-cov>=6.0",
|
|
53
|
+
"httpx>=0.27",
|
|
54
|
+
]
|
|
55
|
+
types = ["mypy>=1.13"]
|
|
56
|
+
audit = ["pip-audit>=2.7"]
|
|
57
|
+
|
|
58
|
+
[build-system]
|
|
59
|
+
requires = ["uv_build>=0.8.0,<0.13"]
|
|
60
|
+
build-backend = "uv_build"
|
|
61
|
+
|
|
62
|
+
# The PyPI distribution is `forge-lens-fl` but the import package stays
|
|
63
|
+
# `forge_lens` — without this, uv_build expects src/forge_lens_fl/.
|
|
64
|
+
[tool.uv.build-backend]
|
|
65
|
+
module-name = "forge_lens"
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
line-length = 100
|
|
69
|
+
target-version = "py311"
|
|
70
|
+
src = ["src", "tests"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff.lint]
|
|
73
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM", "C4", "RUF", "S", "DTZ", "PT", "PTH", "TID"]
|
|
74
|
+
ignore = [
|
|
75
|
+
"S608", # SQL is built from fixed fragments + parameters only
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint.per-file-ignores]
|
|
79
|
+
# Vendored shared bootstrap — canonical copy in forge-doctor-api is the lint target.
|
|
80
|
+
"scripts/forge_bootstrap.py" = ["ALL"]
|
|
81
|
+
# Lab emitter parses its own just-written junit artifact — not untrusted input.
|
|
82
|
+
"scripts/lab/forge_lens_lab.py" = ["S314"]
|
|
83
|
+
"tests/**" = ["S101", "PT011", "PTH", "S105", "S106"]
|
|
84
|
+
"examples/**" = ["S101", "T201"]
|
|
85
|
+
# Homologation runner — subprocess/urllib against the local install is the point.
|
|
86
|
+
"homolog/**" = ["S101", "S105", "S310", "S603", "PTH"]
|
|
87
|
+
"src/forge_lens/cli/**" = ["T201"]
|
|
88
|
+
# Vendored Forge UI kit (canonical: the-forge/src/theforge/ui) —
|
|
89
|
+
# byte-identical to the shared source; linted in the canonical repo.
|
|
90
|
+
"src/forge_lens/ui/**/*.py" = ["ALL"]
|
|
91
|
+
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
testpaths = ["tests"]
|
|
94
|
+
addopts = "-q"
|
|
95
|
+
markers = [
|
|
96
|
+
"e2e: end-to-end scenarios",
|
|
97
|
+
"contract: contract and schema tests",
|
|
98
|
+
"benchmark: benchmark smoke tests (tests/bench)",
|
|
99
|
+
"network: legitimately opens sockets (exempt from the offline gate)",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[tool.coverage.run]
|
|
103
|
+
source = ["src/forge_lens"]
|
|
104
|
+
omit = ["tests/*"]
|
|
105
|
+
|
|
106
|
+
[tool.coverage.report]
|
|
107
|
+
show_missing = true
|
|
108
|
+
exclude_also = ["if TYPE_CHECKING:", "raise NotImplementedError", "@overload"]
|
|
109
|
+
|
|
110
|
+
[tool.mypy]
|
|
111
|
+
python_version = "3.11"
|
|
112
|
+
mypy_path = "src"
|
|
113
|
+
packages = ["forge_lens"]
|
|
114
|
+
strict = true
|
|
115
|
+
warn_unreachable = true
|
|
116
|
+
# Vendored Forge UI kit — mesma razão da exclusão de lint.
|
|
117
|
+
exclude = ["forge_lens.ui"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Honest host capability matrix — Cycle 10.
|
|
2
|
+
|
|
3
|
+
Every host entry states WHAT is actually instrumentable, through which
|
|
4
|
+
mechanism. 'unsupported' is a valid answer — the matrix exists so
|
|
5
|
+
nobody claims coverage that doesn't exist.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
HOST_CAPABILITIES: dict[str, dict[str, Any]] = {
|
|
13
|
+
"claude_code": {
|
|
14
|
+
"native_tracing": False,
|
|
15
|
+
"mechanism": "hooks + session JSONL logs",
|
|
16
|
+
"adapter": "adapters.claude_code (JSONL import → Trace)",
|
|
17
|
+
"coverage": "tool calls, model usage, session boundaries",
|
|
18
|
+
"limits": "no in-process span capture; log-derived only",
|
|
19
|
+
},
|
|
20
|
+
"codex": {
|
|
21
|
+
"native_tracing": False,
|
|
22
|
+
"mechanism": "session logs / rollout files",
|
|
23
|
+
"adapter": "not implemented — log format unstable",
|
|
24
|
+
"coverage": "none claimed",
|
|
25
|
+
"limits": "unsupported today",
|
|
26
|
+
},
|
|
27
|
+
"devin": {
|
|
28
|
+
"native_tracing": False,
|
|
29
|
+
"mechanism": "unsupported — no public instrumentation surface",
|
|
30
|
+
"adapter": None,
|
|
31
|
+
"coverage": "none",
|
|
32
|
+
"limits": "unsupported",
|
|
33
|
+
},
|
|
34
|
+
"copilot": {
|
|
35
|
+
"native_tracing": False,
|
|
36
|
+
"mechanism": "unsupported — closed surface",
|
|
37
|
+
"adapter": None,
|
|
38
|
+
"coverage": "none",
|
|
39
|
+
"limits": "unsupported",
|
|
40
|
+
},
|
|
41
|
+
"cursor": {
|
|
42
|
+
"native_tracing": False,
|
|
43
|
+
"mechanism": "MCP instrumentation point exists (client-side)",
|
|
44
|
+
"adapter": "forge_lens.mcp_server used as gateway observer",
|
|
45
|
+
"coverage": "MCP tool list/call/result only — NOT agent internals",
|
|
46
|
+
"limits": "MCP traffic only; no claim of full tracing",
|
|
47
|
+
},
|
|
48
|
+
"forge": {
|
|
49
|
+
"native_tracing": True,
|
|
50
|
+
"mechanism": "in-process SDK instrumentation",
|
|
51
|
+
"adapter": "forge_lens.sdk (native)",
|
|
52
|
+
"coverage": "full spans, tools, tokens",
|
|
53
|
+
"limits": "requires opt-in tracing init",
|
|
54
|
+
},
|
|
55
|
+
"generic_otlp": {
|
|
56
|
+
"native_tracing": True,
|
|
57
|
+
"mechanism": "OTLP/HTTP JSON endpoint",
|
|
58
|
+
"adapter": "built-in",
|
|
59
|
+
"coverage": "whatever the runtime emits",
|
|
60
|
+
"limits": "span quality depends on emitter",
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def capability_matrix() -> dict[str, Any]:
|
|
66
|
+
return {
|
|
67
|
+
"hosts": {k: dict(v) for k, v in sorted(HOST_CAPABILITIES.items())},
|
|
68
|
+
"note": "coverage claims are per-mechanism; 'unsupported' means"
|
|
69
|
+
" no verified path exists today",
|
|
70
|
+
}
|