tokenjam 0.2.0__tar.gz → 0.2.1__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.
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.gitignore +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/CHANGELOG.md +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/CLAUDE.md +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/Makefile +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/PKG-INFO +30 -30
- {tokenjam-0.2.0 → tokenjam-0.2.1}/README.md +29 -29
- {tokenjam-0.2.0 → tokenjam-0.2.1}/SECURITY.md +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/alerts.md +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/architecture.md +15 -15
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/claude-code-integration.md +7 -7
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/cli-reference.md +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/configuration.md +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/export.md +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/framework-support.md +13 -13
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/nemoclaw-integration.md +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/docs/openclaw.md +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/README.md +15 -15
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/alerts_and_drift/_shared.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/alerts_and_drift/budget_breach_demo.py +12 -12
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/alerts_and_drift/drift_demo.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/alerts_and_drift/sensitive_actions_demo.py +10 -10
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/rag_pipeline.py +9 -9
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/research_team.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/router_agent.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/openclaw/README.md +12 -12
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_framework/autogen_agent.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_framework/crewai_agent.py +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_framework/langchain_agent.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_framework/langgraph_agent.py +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_framework/llamaindex_agent.py +10 -10
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/anthropic_agent.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/bedrock_agent.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/gemini_agent.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/litellm_agent.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/openai_agent.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/single_provider/openai_agents_sdk_agent.py +14 -14
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/hallucination-drift/BLOG.md +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/hallucination-drift/README.md +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/hallucination-drift/scenario.py +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/retry-loop/BLOG.md +3 -3
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/retry-loop/README.md +3 -3
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/retry-loop/scenario.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/surprise-cost/BLOG.md +5 -5
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/surprise-cost/README.md +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/incidents/surprise-cost/scenario.py +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/pyproject.toml +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/README.md +13 -13
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/package-lock.json +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/package.json +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/client.test.ts +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/client.ts +6 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/semconv.test.ts +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/semconv.ts +10 -10
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/types.ts +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_api.py +2 -2
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_cli.py +9 -9
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_demos.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/manual-new-release-tests.md +50 -47
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/manual-pre-release-testing.md +79 -76
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/test_ingest.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/test_schema_validation.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_cmd_stop.py +4 -4
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_cost.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_litellm_integration.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_mcp_server.py +1 -1
- tokenjam-0.2.1/tests/unit/test_onboard_codex.py +150 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_onboard_daemon.py +2 -2
- tokenjam-0.2.1/tests/unit/test_spans_stats_repair.py +99 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/app.py +8 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/metrics.py +11 -11
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_demo.py +1 -1
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_doctor.py +107 -7
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_mcp.py +3 -3
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_onboard.py +66 -6
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_serve.py +20 -13
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_uninstall.py +13 -13
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/db.py +66 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/mcp/server.py +10 -10
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/bootstrap.py +3 -3
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/nemoclaw.py +7 -7
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/ui/index.html +146 -66
- tokenjam-0.2.0/.tj/config.toml +0 -27
- tokenjam-0.2.0/tests/unit/test_onboard_codex.py +0 -34
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/CODEOWNERS +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/ISSUE_TEMPLATE/integration_request.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/pull_request_template.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/workflows/ci.yml +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/workflows/publish-npm.yml +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/.github/workflows/publish-pypi.yml +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/AGENTS.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/CONTRIBUTING.md +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/LICENSE +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/sample_docs/agent_patterns.txt +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/sample_docs/cost_management.txt +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/sample_docs/observability.txt +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/examples/multi/sample_docs/safety.txt +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/pricing/models.toml +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/index.ts +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/span-builder.test.ts +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/src/span-builder.ts +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/sdk-ts/tsconfig.json +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/email_agent_budget_breach.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/email_agent_drift.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/email_agent_loop.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/email_agent_normal.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/mock_llm.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/agents/test_mock_scenarios.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/conftest.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/e2e/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/e2e/conftest.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/e2e/test_real_llm.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/factories.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_db.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_full_pipeline.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/integration/test_logs_api.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/test_alert_rules.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/test_cost_tracking.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/synthetic/test_drift_detection.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/toy_agent/toy_agent.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_alerts.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_config.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_demo_env.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_demo_scenarios.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_drift.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_formatting.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_logs_converter.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_models.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_openclaw_ingest.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tests/unit/test_time_parse.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/deps.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/middleware.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/agents.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/alerts.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/budget.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/cost.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/drift.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/logs.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/otlp.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/spans.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/status.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/tools.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/api/routes/traces.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_alerts.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_budget.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_cost.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_drift.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_export.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_status.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_stop.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_tools.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/cmd_traces.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/cli/main.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/alerts.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/api_backend.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/config.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/cost.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/drift.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/ingest.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/models.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/pricing.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/retention.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/core/schema_validator.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/demo/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/demo/env.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/mcp/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/otel/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/otel/exporters.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/otel/provider.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/otel/semconv.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/pricing/models.toml +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/py.typed +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/agent.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/http_exporter.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/anthropic.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/autogen.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/base.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/bedrock.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/crewai.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/gemini.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/langchain.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/langgraph.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/litellm.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/llamaindex.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/openai.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/integrations/openai_agents_sdk.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/sdk/transport.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/utils/__init__.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/utils/formatting.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/utils/ids.py +0 -0
- {tokenjam-0.2.0 → tokenjam-0.2.1}/tokenjam/utils/time_parse.py +0 -0
|
@@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
8
8
|
## [0.1.7] - 2026-04-13
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
|
-
- **MCP server (`tj mcp`)** — stdio-based Model Context Protocol server giving Claude Code direct access to
|
|
11
|
+
- **MCP server (`tj mcp`)** — stdio-based Model Context Protocol server giving Claude Code direct access to TokenJam observability data. 13 tool handlers: status, traces, alerts, budget headroom, cost summary, drift report, tool stats, trace detail, acknowledge alerts, setup project, list sessions, open dashboard. Dual-mode operation: routes queries through REST API when `tj serve` is running, falls back to read-only DuckDB otherwise. Auto-starts `tj serve` on demand.
|
|
12
12
|
- **Claude Code integration (`tj onboard --claude-code`)** — one-command setup for Claude Code telemetry. Configures OTLP log exporter in `~/.claude/settings.json`, sets project-level `OTEL_RESOURCE_ATTRIBUTES`, adds Docker-compatible endpoint to shell env, and optionally installs background daemon. Re-runs resync the auth header to fix 401s without manual setup.
|
|
13
13
|
- **Logs ingestion (`POST /v1/logs`)** — new OTLP log endpoint that converts Claude Code log events (`api_request`, `tool_result`, `api_error`, `user_prompt`, `tool_decision`) into NormalizedSpans with deterministic trace/span IDs. Spans flow through the standard ingest pipeline for cost, alerts, and drift.
|
|
14
14
|
- **`tj drift` CLI** — behavioral drift report with Rich table output showing baseline vs latest session Z-scores per dimension (input tokens, output tokens, duration, tool call count, tool sequence similarity). Color-coded thresholds, `--json` support, exit code 1 if drift detected.
|
|
@@ -106,7 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
106
106
|
|
|
107
107
|
### Added
|
|
108
108
|
- `tj stop` command — graceful shutdown of daemon or background process
|
|
109
|
-
- `tj uninstall` command — clean removal of all
|
|
109
|
+
- `tj uninstall` command — clean removal of all TokenJam data, config, and daemon
|
|
110
110
|
- 16 runnable example agents across 4 tiers: single provider, single framework, multi-agent, and alerts/drift demos
|
|
111
111
|
- API fallback backend (`ApiBackend`) so CLI works while `tj serve` holds the DB lock
|
|
112
112
|
|
|
@@ -127,7 +127,7 @@ Post-ingest hooks run synchronously after each span is written to DB:
|
|
|
127
127
|
| `tj drift` | `cmd_drift.py` | Show drift baselines and Z-scores for recent sessions |
|
|
128
128
|
| `tj demo [scenario]` | `cmd_demo.py` | Run Agent Incident Library scenarios (zero-config, no API keys). `tj demo` lists all; `tj demo retry-loop` runs one |
|
|
129
129
|
| `tj mcp` | `cmd_mcp.py` | Start the stdio MCP server for Claude Code integration |
|
|
130
|
-
| `tj uninstall` | `cmd_uninstall.py` | Remove all
|
|
130
|
+
| `tj uninstall` | `cmd_uninstall.py` | Remove all TokenJam data, config, and daemon |
|
|
131
131
|
| `tj doctor` | `cmd_doctor.py` | Health checks (config, DB, secrets, webhooks, drift readiness, schema-vs-capture consistency). Exit 0 = ok, 1 = warnings, 2 = errors |
|
|
132
132
|
|
|
133
133
|
All commands support `--json` for machine-readable output. Commands that query alerts use exit code 1 if active (unacknowledged, unsuppressed) alerts exist.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tokenjam
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: TokenJam — local-first OTel-native observability for Autonomous AI agents
|
|
5
5
|
Project-URL: Homepage, https://opencla.watch
|
|
6
6
|
Project-URL: Repository, https://github.com/Metabuilder-Labs/openclawwatch
|
|
@@ -56,7 +56,7 @@ Description-Content-Type: text/markdown
|
|
|
56
56
|
|
|
57
57
|
<div align="center">
|
|
58
58
|
|
|
59
|
-
<img src="https://
|
|
59
|
+
<img src="https://tokenjam.dev/icon.svg" alt="TokenJam" width="72" height="72">
|
|
60
60
|
|
|
61
61
|
# TokenJam
|
|
62
62
|
|
|
@@ -122,7 +122,7 @@ For any Python agent — Anthropic, OpenAI, Gemini, Bedrock, LangChain, CrewAI,
|
|
|
122
122
|
```bash
|
|
123
123
|
pip install tokenjam
|
|
124
124
|
tj onboard # creates config, generates ingest secret
|
|
125
|
-
|
|
125
|
+
tj doctor # verify your setup
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
```python
|
|
@@ -211,12 +211,12 @@ https://github.com/user-attachments/assets/b94d13f6-1432-40d4-b093-6958d74f0e65
|
|
|
211
211
|
|
|
212
212
|
```bash
|
|
213
213
|
tj status # current state, cost, active alerts
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
tj traces # full span history with waterfall view
|
|
215
|
+
tj cost --since 7d # cost breakdown by agent, model, day
|
|
216
|
+
tj alerts # everything that fired while you were away
|
|
217
|
+
tj budget # view and set daily/session cost limits
|
|
218
|
+
tj drift # behavioral drift Z-scores vs baseline
|
|
219
|
+
tj tools # tool call history with error rates
|
|
220
220
|
tj serve # start the web UI + REST API
|
|
221
221
|
```
|
|
222
222
|
|
|
@@ -239,7 +239,7 @@ No signup, no cloud — runs entirely on your machine.
|
|
|
239
239
|
|
|
240
240
|
---
|
|
241
241
|
|
|
242
|
-
##
|
|
242
|
+
## tj vs LangSmith vs Langfuse
|
|
243
243
|
|
|
244
244
|
LangSmith and Langfuse are excellent for tracing LLM API calls and running evals on chat outputs. `tj` solves a different problem: **autonomous agents running unsupervised with real-world consequences**.
|
|
245
245
|
|
|
@@ -307,14 +307,14 @@ The MCP server gives Claude Code direct access to your observability data inside
|
|
|
307
307
|
| `get_tool_stats` | Tool call counts and average duration |
|
|
308
308
|
| `get_drift_report` | Drift baseline vs latest session |
|
|
309
309
|
| `acknowledge_alert` | Mark an alert as acknowledged |
|
|
310
|
-
| `setup_project` | Configure a project for
|
|
310
|
+
| `setup_project` | Configure a project for TokenJam telemetry |
|
|
311
311
|
| `open_dashboard` | Open the web UI (starts `tj serve` if needed) |
|
|
312
312
|
|
|
313
313
|
The MCP server opens DuckDB read-only — no lock conflicts with `tj serve`.
|
|
314
314
|
|
|
315
315
|
**Per-project tagging** — after installing globally, ask Claude Code:
|
|
316
316
|
|
|
317
|
-
> "Set up
|
|
317
|
+
> "Set up TokenJam for this project"
|
|
318
318
|
|
|
319
319
|
Claude calls `setup_project`, which writes `.claude/settings.json` with the right `OTEL_RESOURCE_ATTRIBUTES` for this project.
|
|
320
320
|
|
|
@@ -330,8 +330,8 @@ tj onboard --codex
|
|
|
330
330
|
`tj onboard --codex` is project-agnostic. It writes to `~/.codex/config.toml` (Codex's single global config), so you only run it once — not once per project. Codex hardcodes `service.name="codex_exec"` in its binary, so all sessions appear under the same agent ID regardless of which repo you're working in.
|
|
331
331
|
|
|
332
332
|
`tj onboard --codex`:
|
|
333
|
-
- Writes an `[otel]` block and `[mcp_servers.
|
|
334
|
-
- Registers the MCP server so Codex can call
|
|
333
|
+
- Writes an `[otel]` block and `[mcp_servers.tj]` to `~/.codex/config.toml`
|
|
334
|
+
- Registers the MCP server so Codex can call TokenJam tools directly
|
|
335
335
|
- Installs the background daemon (launchd / systemd)
|
|
336
336
|
|
|
337
337
|
**Codex must be restarted** after running `tj onboard --codex`.
|
|
@@ -345,14 +345,14 @@ The same 13 MCP tools available to Claude Code are available to Codex after rest
|
|
|
345
345
|
### Uninstalling
|
|
346
346
|
|
|
347
347
|
```bash
|
|
348
|
-
# Remove all
|
|
349
|
-
|
|
348
|
+
# Remove all TokenJam data, config, daemon, MCP registration, and env vars:
|
|
349
|
+
tj uninstall --yes
|
|
350
350
|
|
|
351
351
|
# Then remove the package:
|
|
352
352
|
pip uninstall tokenjam -y
|
|
353
353
|
```
|
|
354
354
|
|
|
355
|
-
`tj uninstall` cleans up everything set by `tj onboard --claude-code`: daemon, MCP server, `~/.
|
|
355
|
+
`tj uninstall` cleans up everything set by `tj onboard --claude-code`: daemon, MCP server, `~/.tj/`, `~/.config/tj/`, OTLP env vars in `~/.claude/settings.json`, `OTEL_RESOURCE_ATTRIBUTES` in every onboarded project's `.claude/settings.json`, and the harness env block in `~/.zshrc`.
|
|
356
356
|
|
|
357
357
|
---
|
|
358
358
|
|
|
@@ -397,7 +397,7 @@ Full framework support guide: [docs/framework-support.md](docs/framework-support
|
|
|
397
397
|
Configure where alerts go. Multiple channels work simultaneously.
|
|
398
398
|
|
|
399
399
|
```toml
|
|
400
|
-
# .
|
|
400
|
+
# .tj/config.toml
|
|
401
401
|
|
|
402
402
|
[[alerts.channels]]
|
|
403
403
|
type = "ntfy"
|
|
@@ -438,10 +438,10 @@ Full event table and configuration: [docs/nemoclaw-integration.md](docs/nemoclaw
|
|
|
438
438
|
## Export and integrate
|
|
439
439
|
|
|
440
440
|
```bash
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
441
|
+
tj export --format otlp # forward to Grafana, Datadog, any OTel backend
|
|
442
|
+
tj export --format openevals # openevals / agentevals trajectory evaluation
|
|
443
|
+
tj export --format json # NDJSON
|
|
444
|
+
tj export --format csv
|
|
445
445
|
```
|
|
446
446
|
|
|
447
447
|
Prometheus metrics at `http://127.0.0.1:7391/metrics` when `tj serve` is running.
|
|
@@ -478,7 +478,7 @@ flowchart TD
|
|
|
478
478
|
Alerts --> DB
|
|
479
479
|
Schema --> DB
|
|
480
480
|
|
|
481
|
-
DB --> CLI["
|
|
481
|
+
DB --> CLI["tj CLI"]
|
|
482
482
|
DB --> API["REST API + Web UI\n:7391"]
|
|
483
483
|
DB --> MCP["MCP Server\n13 tools"]
|
|
484
484
|
DB --> Prom["Prometheus\n:7391/metrics"]
|
|
@@ -491,7 +491,7 @@ Full architecture deep-dive — design principles, SDK internals, alert system,
|
|
|
491
491
|
## Configuration
|
|
492
492
|
|
|
493
493
|
```toml
|
|
494
|
-
# .
|
|
494
|
+
# .tj/config.toml — generated by tj onboard
|
|
495
495
|
|
|
496
496
|
[defaults.budget]
|
|
497
497
|
daily_usd = 10.00
|
|
@@ -518,7 +518,7 @@ completions = false
|
|
|
518
518
|
tool_outputs = false
|
|
519
519
|
|
|
520
520
|
[storage]
|
|
521
|
-
path = "~/.
|
|
521
|
+
path = "~/.tj/telemetry.duckdb"
|
|
522
522
|
retention_days = 90
|
|
523
523
|
```
|
|
524
524
|
|
|
@@ -559,18 +559,18 @@ See [`examples/README.md`](examples/README.md) for the full list.
|
|
|
559
559
|
Reproducible AI agent failures you can run in 30 seconds. No API keys, no config, no setup.
|
|
560
560
|
|
|
561
561
|
```bash
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
562
|
+
tj demo # list all scenarios
|
|
563
|
+
tj demo retry-loop # run one
|
|
564
|
+
tj demo retry-loop --json # machine-readable output
|
|
565
565
|
```
|
|
566
566
|
|
|
567
|
-
| Scenario | What goes wrong | What
|
|
567
|
+
| Scenario | What goes wrong | What TokenJam catches |
|
|
568
568
|
|---|---|---|
|
|
569
569
|
| [`retry-loop`](incidents/retry-loop/README.md) | Agent retries a failing tool in a loop, burning time and tokens | `retry_loop` + `failure_rate` alerts fire automatically |
|
|
570
570
|
| [`surprise-cost`](incidents/surprise-cost/README.md) | Model silently escalates from Haiku to Opus mid-chain | Per-model cost breakdown shows the $3+ you didn't expect |
|
|
571
571
|
| [`hallucination-drift`](incidents/hallucination-drift/README.md) | Agent behavior shifts — different tokens, different tools | `drift_detected` alert fires with Z-scores at session end |
|
|
572
572
|
|
|
573
|
-
Each scenario runs against an in-memory backend and produces a side-by-side comparison: what `print()` shows vs. what
|
|
573
|
+
Each scenario runs against an in-memory backend and produces a side-by-side comparison: what `print()` shows vs. what TokenJam reveals.
|
|
574
574
|
|
|
575
575
|
---
|
|
576
576
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="https://
|
|
3
|
+
<img src="https://tokenjam.dev/icon.svg" alt="TokenJam" width="72" height="72">
|
|
4
4
|
|
|
5
5
|
# TokenJam
|
|
6
6
|
|
|
@@ -66,7 +66,7 @@ For any Python agent — Anthropic, OpenAI, Gemini, Bedrock, LangChain, CrewAI,
|
|
|
66
66
|
```bash
|
|
67
67
|
pip install tokenjam
|
|
68
68
|
tj onboard # creates config, generates ingest secret
|
|
69
|
-
|
|
69
|
+
tj doctor # verify your setup
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
```python
|
|
@@ -155,12 +155,12 @@ https://github.com/user-attachments/assets/b94d13f6-1432-40d4-b093-6958d74f0e65
|
|
|
155
155
|
|
|
156
156
|
```bash
|
|
157
157
|
tj status # current state, cost, active alerts
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
tj traces # full span history with waterfall view
|
|
159
|
+
tj cost --since 7d # cost breakdown by agent, model, day
|
|
160
|
+
tj alerts # everything that fired while you were away
|
|
161
|
+
tj budget # view and set daily/session cost limits
|
|
162
|
+
tj drift # behavioral drift Z-scores vs baseline
|
|
163
|
+
tj tools # tool call history with error rates
|
|
164
164
|
tj serve # start the web UI + REST API
|
|
165
165
|
```
|
|
166
166
|
|
|
@@ -183,7 +183,7 @@ No signup, no cloud — runs entirely on your machine.
|
|
|
183
183
|
|
|
184
184
|
---
|
|
185
185
|
|
|
186
|
-
##
|
|
186
|
+
## tj vs LangSmith vs Langfuse
|
|
187
187
|
|
|
188
188
|
LangSmith and Langfuse are excellent for tracing LLM API calls and running evals on chat outputs. `tj` solves a different problem: **autonomous agents running unsupervised with real-world consequences**.
|
|
189
189
|
|
|
@@ -251,14 +251,14 @@ The MCP server gives Claude Code direct access to your observability data inside
|
|
|
251
251
|
| `get_tool_stats` | Tool call counts and average duration |
|
|
252
252
|
| `get_drift_report` | Drift baseline vs latest session |
|
|
253
253
|
| `acknowledge_alert` | Mark an alert as acknowledged |
|
|
254
|
-
| `setup_project` | Configure a project for
|
|
254
|
+
| `setup_project` | Configure a project for TokenJam telemetry |
|
|
255
255
|
| `open_dashboard` | Open the web UI (starts `tj serve` if needed) |
|
|
256
256
|
|
|
257
257
|
The MCP server opens DuckDB read-only — no lock conflicts with `tj serve`.
|
|
258
258
|
|
|
259
259
|
**Per-project tagging** — after installing globally, ask Claude Code:
|
|
260
260
|
|
|
261
|
-
> "Set up
|
|
261
|
+
> "Set up TokenJam for this project"
|
|
262
262
|
|
|
263
263
|
Claude calls `setup_project`, which writes `.claude/settings.json` with the right `OTEL_RESOURCE_ATTRIBUTES` for this project.
|
|
264
264
|
|
|
@@ -274,8 +274,8 @@ tj onboard --codex
|
|
|
274
274
|
`tj onboard --codex` is project-agnostic. It writes to `~/.codex/config.toml` (Codex's single global config), so you only run it once — not once per project. Codex hardcodes `service.name="codex_exec"` in its binary, so all sessions appear under the same agent ID regardless of which repo you're working in.
|
|
275
275
|
|
|
276
276
|
`tj onboard --codex`:
|
|
277
|
-
- Writes an `[otel]` block and `[mcp_servers.
|
|
278
|
-
- Registers the MCP server so Codex can call
|
|
277
|
+
- Writes an `[otel]` block and `[mcp_servers.tj]` to `~/.codex/config.toml`
|
|
278
|
+
- Registers the MCP server so Codex can call TokenJam tools directly
|
|
279
279
|
- Installs the background daemon (launchd / systemd)
|
|
280
280
|
|
|
281
281
|
**Codex must be restarted** after running `tj onboard --codex`.
|
|
@@ -289,14 +289,14 @@ The same 13 MCP tools available to Claude Code are available to Codex after rest
|
|
|
289
289
|
### Uninstalling
|
|
290
290
|
|
|
291
291
|
```bash
|
|
292
|
-
# Remove all
|
|
293
|
-
|
|
292
|
+
# Remove all TokenJam data, config, daemon, MCP registration, and env vars:
|
|
293
|
+
tj uninstall --yes
|
|
294
294
|
|
|
295
295
|
# Then remove the package:
|
|
296
296
|
pip uninstall tokenjam -y
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
-
`tj uninstall` cleans up everything set by `tj onboard --claude-code`: daemon, MCP server, `~/.
|
|
299
|
+
`tj uninstall` cleans up everything set by `tj onboard --claude-code`: daemon, MCP server, `~/.tj/`, `~/.config/tj/`, OTLP env vars in `~/.claude/settings.json`, `OTEL_RESOURCE_ATTRIBUTES` in every onboarded project's `.claude/settings.json`, and the harness env block in `~/.zshrc`.
|
|
300
300
|
|
|
301
301
|
---
|
|
302
302
|
|
|
@@ -341,7 +341,7 @@ Full framework support guide: [docs/framework-support.md](docs/framework-support
|
|
|
341
341
|
Configure where alerts go. Multiple channels work simultaneously.
|
|
342
342
|
|
|
343
343
|
```toml
|
|
344
|
-
# .
|
|
344
|
+
# .tj/config.toml
|
|
345
345
|
|
|
346
346
|
[[alerts.channels]]
|
|
347
347
|
type = "ntfy"
|
|
@@ -382,10 +382,10 @@ Full event table and configuration: [docs/nemoclaw-integration.md](docs/nemoclaw
|
|
|
382
382
|
## Export and integrate
|
|
383
383
|
|
|
384
384
|
```bash
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
385
|
+
tj export --format otlp # forward to Grafana, Datadog, any OTel backend
|
|
386
|
+
tj export --format openevals # openevals / agentevals trajectory evaluation
|
|
387
|
+
tj export --format json # NDJSON
|
|
388
|
+
tj export --format csv
|
|
389
389
|
```
|
|
390
390
|
|
|
391
391
|
Prometheus metrics at `http://127.0.0.1:7391/metrics` when `tj serve` is running.
|
|
@@ -422,7 +422,7 @@ flowchart TD
|
|
|
422
422
|
Alerts --> DB
|
|
423
423
|
Schema --> DB
|
|
424
424
|
|
|
425
|
-
DB --> CLI["
|
|
425
|
+
DB --> CLI["tj CLI"]
|
|
426
426
|
DB --> API["REST API + Web UI\n:7391"]
|
|
427
427
|
DB --> MCP["MCP Server\n13 tools"]
|
|
428
428
|
DB --> Prom["Prometheus\n:7391/metrics"]
|
|
@@ -435,7 +435,7 @@ Full architecture deep-dive — design principles, SDK internals, alert system,
|
|
|
435
435
|
## Configuration
|
|
436
436
|
|
|
437
437
|
```toml
|
|
438
|
-
# .
|
|
438
|
+
# .tj/config.toml — generated by tj onboard
|
|
439
439
|
|
|
440
440
|
[defaults.budget]
|
|
441
441
|
daily_usd = 10.00
|
|
@@ -462,7 +462,7 @@ completions = false
|
|
|
462
462
|
tool_outputs = false
|
|
463
463
|
|
|
464
464
|
[storage]
|
|
465
|
-
path = "~/.
|
|
465
|
+
path = "~/.tj/telemetry.duckdb"
|
|
466
466
|
retention_days = 90
|
|
467
467
|
```
|
|
468
468
|
|
|
@@ -503,18 +503,18 @@ See [`examples/README.md`](examples/README.md) for the full list.
|
|
|
503
503
|
Reproducible AI agent failures you can run in 30 seconds. No API keys, no config, no setup.
|
|
504
504
|
|
|
505
505
|
```bash
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
506
|
+
tj demo # list all scenarios
|
|
507
|
+
tj demo retry-loop # run one
|
|
508
|
+
tj demo retry-loop --json # machine-readable output
|
|
509
509
|
```
|
|
510
510
|
|
|
511
|
-
| Scenario | What goes wrong | What
|
|
511
|
+
| Scenario | What goes wrong | What TokenJam catches |
|
|
512
512
|
|---|---|---|
|
|
513
513
|
| [`retry-loop`](incidents/retry-loop/README.md) | Agent retries a failing tool in a loop, burning time and tokens | `retry_loop` + `failure_rate` alerts fire automatically |
|
|
514
514
|
| [`surprise-cost`](incidents/surprise-cost/README.md) | Model silently escalates from Haiku to Opus mid-chain | Per-model cost breakdown shows the $3+ you didn't expect |
|
|
515
515
|
| [`hallucination-drift`](incidents/hallucination-drift/README.md) | Agent behavior shifts — different tokens, different tools | `drift_detected` alert fires with Z-scores at session end |
|
|
516
516
|
|
|
517
|
-
Each scenario runs against an in-memory backend and produces a side-by-side comparison: what `print()` shows vs. what
|
|
517
|
+
Each scenario runs against an in-memory backend and produces a side-by-side comparison: what `print()` shows vs. what TokenJam reveals.
|
|
518
518
|
|
|
519
519
|
---
|
|
520
520
|
|
|
@@ -26,4 +26,4 @@ Security issues in these areas are especially important to report.
|
|
|
26
26
|
## Not in Scope
|
|
27
27
|
|
|
28
28
|
- Vulnerabilities in upstream dependencies (report to the upstream project)
|
|
29
|
-
- Issues that require physical access to the machine running `
|
|
29
|
+
- Issues that require physical access to the machine running `tj`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Alerts
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`tj` fires alerts the moment something happens — sensitive tool calls, budget breaches, behavioral drift, sandbox violations. Alerts are evaluated after every span ingest and dispatched to your configured channels in real time.
|
|
4
4
|
|
|
5
5
|
## Alert types
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
## Channels
|
|
24
24
|
|
|
25
|
-
Configure where alerts go in `.
|
|
25
|
+
Configure where alerts go in `.tj/config.toml`. Multiple channels work simultaneously — you can get push notifications on your phone and a Discord message at the same time.
|
|
26
26
|
|
|
27
27
|
```toml
|
|
28
28
|
# Push notification (free, no account required)
|
|
@@ -49,7 +49,7 @@ url = "https://your-endpoint.com/alerts"
|
|
|
49
49
|
# Local file log
|
|
50
50
|
[[alerts.channels]]
|
|
51
51
|
type = "file"
|
|
52
|
-
path = "~/.
|
|
52
|
+
path = "~/.tj/alerts.log"
|
|
53
53
|
|
|
54
54
|
# Stdout (always enabled by default)
|
|
55
55
|
[[alerts.channels]]
|
|
@@ -77,7 +77,7 @@ Define which tool calls should trigger immediate alerts:
|
|
|
77
77
|
|
|
78
78
|
## Cooldown
|
|
79
79
|
|
|
80
|
-
To prevent alert storms, `
|
|
80
|
+
To prevent alert storms, `tj` tracks a cooldown per agent + alert type. Repeat alerts within the cooldown window are suppressed — still persisted to the database, but not dispatched to channels.
|
|
81
81
|
|
|
82
82
|
```toml
|
|
83
83
|
[alerts]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
This document describes the architecture of TokenJam (
|
|
3
|
+
This document describes the architecture of TokenJam (`tj`) — a local-first, OTel-native observability CLI for autonomous AI agents.
|
|
4
4
|
|
|
5
5
|
## Design principles
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ This document describes the architecture of TokenJam (ocw) — a local-first, OT
|
|
|
10
10
|
|
|
11
11
|
3. **Never crash the agent.** The SDK, ingest pipeline, and all post-ingest hooks are designed to fail silently. Hook failures are logged but never propagated. A span rejection never takes down the instrumented agent.
|
|
12
12
|
|
|
13
|
-
4. **Core is pure domain logic.** `
|
|
13
|
+
4. **Core is pure domain logic.** `tokenjam/core/` has no CLI or HTTP imports. CLI and API layers import from core, never the reverse. This makes the domain logic independently testable and reusable.
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -42,7 +42,7 @@ flowchart TD
|
|
|
42
42
|
Alerts --> DB
|
|
43
43
|
Schema --> DB
|
|
44
44
|
|
|
45
|
-
DB --> CLI["
|
|
45
|
+
DB --> CLI["tj CLI"]
|
|
46
46
|
DB --> API["REST API\n:7391/docs"]
|
|
47
47
|
DB --> WebUI["Web UI\n:7391/"]
|
|
48
48
|
DB --> MCP["MCP Server\nstdio"]
|
|
@@ -91,7 +91,7 @@ Sessions are identified by `conversation_id`. When a span arrives with a `conver
|
|
|
91
91
|
## Package structure and dependency rules
|
|
92
92
|
|
|
93
93
|
```
|
|
94
|
-
|
|
94
|
+
tokenjam/
|
|
95
95
|
├── core/ Pure domain logic — NO imports from cli/ or api/
|
|
96
96
|
├── cli/ Click commands — imports from core/
|
|
97
97
|
├── api/ FastAPI routes — imports from core/
|
|
@@ -141,7 +141,7 @@ DuckDB allows only one write connection. When `tj serve` is running, CLI command
|
|
|
141
141
|
|
|
142
142
|
### Bootstrap
|
|
143
143
|
|
|
144
|
-
`ensure_initialised()` in `
|
|
144
|
+
`ensure_initialised()` in `tokenjam/sdk/bootstrap.py` is the lazy, thread-safe, idempotent entry point. It bootstraps: config loading → DB connection → IngestPipeline creation → TracerProvider setup. Called automatically by `@watch()` and all `patch_*()` functions. Registers an `atexit` handler to flush pending spans.
|
|
145
145
|
|
|
146
146
|
### @watch() creates sessions, not LLM spans
|
|
147
147
|
|
|
@@ -256,7 +256,7 @@ A stub endpoint at `/v1/metrics` returns 200 OK to prevent noisy warnings from O
|
|
|
256
256
|
|
|
257
257
|
## Web UI
|
|
258
258
|
|
|
259
|
-
A single-file SPA (`
|
|
259
|
+
A single-file SPA (`tokenjam/ui/index.html`) served by `tj serve` at `http://127.0.0.1:7391/`. No build step, no node_modules — vanilla JS with Alpine.js from CDN.
|
|
260
260
|
|
|
261
261
|
Six views: Status, Traces (with span waterfall visualization), Cost, Alerts, Budget, Drift. Hash-based routing (`/#/status`, `/#/traces`, etc.). The UI consumes the same REST API endpoints as external clients. All views auto-poll (Status at 5s, all others at 10s).
|
|
262
262
|
|
|
@@ -287,7 +287,7 @@ A fifth layer (`tests/e2e/`) makes real LLM API calls and is auto-skipped withou
|
|
|
287
287
|
|
|
288
288
|
- **OTel TracerProvider:** Global and set-once per process. In SDK tests, set the provider once at module level (not per-test) and clear spans between tests using a custom `_CollectingExporter`.
|
|
289
289
|
|
|
290
|
-
- **CLI tests:** Use `click.testing.CliRunner` with `unittest.mock.patch` on `
|
|
290
|
+
- **CLI tests:** Use `click.testing.CliRunner` with `unittest.mock.patch` on `tokenjam.cli.main.load_config` and `tokenjam.cli.main.open_db` to inject test fixtures.
|
|
291
291
|
|
|
292
292
|
- **API tests:** Use `httpx.AsyncClient` with `httpx.ASGITransport(app=app)` against `InMemoryBackend`.
|
|
293
293
|
|
|
@@ -297,7 +297,7 @@ A fifth layer (`tests/e2e/`) makes real LLM API calls and is auto-skipped withou
|
|
|
297
297
|
|
|
298
298
|
Config is TOML, discovered in order: `tj.toml` → `.tj/config.toml` → `~/.config/tj/config.toml`. Override with `--config` flag or `TJ_CONFIG` env var.
|
|
299
299
|
|
|
300
|
-
The `TjConfig` dataclass tree in `
|
|
300
|
+
The `TjConfig` dataclass tree in `tokenjam/core/config.py` defines the full hierarchy: agents (with budgets, sensitive actions, drift config, output schema), storage, export (OTLP, Prometheus), alerts (cooldown, channels), security, API, and capture settings.
|
|
301
301
|
|
|
302
302
|
`tomllib.load()` requires binary mode (`"rb"`) — text mode raises `TypeError` at runtime. The codebase uses conditional imports: `tomllib` (Python 3.11+) or `tomli` (3.10). Writing config uses `tomli_w`.
|
|
303
303
|
|
|
@@ -305,7 +305,7 @@ The `TjConfig` dataclass tree in `ocw/core/config.py` defines the full hierarchy
|
|
|
305
305
|
|
|
306
306
|
## MCP server (Claude Code integration)
|
|
307
307
|
|
|
308
|
-
`tj mcp` is a stdio-based MCP (Model Context Protocol) server that gives Claude Code direct access to
|
|
308
|
+
`tj mcp` is a stdio-based MCP (Model Context Protocol) server that gives Claude Code direct access to TokenJam observability data. It exposes 13 tools that Claude Code can call during a session.
|
|
309
309
|
|
|
310
310
|
### Dual-mode operation
|
|
311
311
|
|
|
@@ -348,7 +348,7 @@ If `tj serve` is not running, `cmd_mcp.py` can auto-start it as a detached subpr
|
|
|
348
348
|
The `--claude-code` flag configures the full telemetry pipeline in one command:
|
|
349
349
|
|
|
350
350
|
1. **Derives agent ID** from the git remote origin name (fallback: folder name), prefixed with `claude-code-`
|
|
351
|
-
2. **Writes
|
|
351
|
+
2. **Writes TokenJam config** to `~/.config/tj/config.toml` (global, shared across all projects) with agent entry and optional daily budget
|
|
352
352
|
3. **Updates global Claude settings** (`~/.claude/settings.json`) with OTLP exporter env vars: `CLAUDE_CODE_ENABLE_TELEMETRY=1`, `OTEL_LOGS_EXPORTER=otlp`, endpoint, protocol. On re-runs, always resyncs the `OTEL_EXPORTER_OTLP_HEADERS` auth header to fix 401s without manual setup.
|
|
353
353
|
4. **Writes project settings** (`./.claude/settings.json`) with `OTEL_RESOURCE_ATTRIBUTES=service.name={agent_id}` so spans are tagged to the right agent
|
|
354
354
|
5. **Updates shell env** (`~/.zshrc`) with Docker-compatible endpoint (`host.docker.internal:{port}`) for harness sessions that can't reach `127.0.0.1`
|
|
@@ -373,7 +373,7 @@ The converted spans flow through the standard `IngestPipeline.process()` path
|
|
|
373
373
|
|
|
374
374
|
### Semantic conventions (`ClaudeCodeEvents`)
|
|
375
375
|
|
|
376
|
-
`
|
|
376
|
+
`tokenjam/otel/semconv.py` defines `ClaudeCodeEvents` constants for Claude Code's log event attributes: session context (`session.id`, `prompt.id`, `event.sequence`), API request metrics (`cost_usd`, `duration_ms`, `speed`, token counts), tool result fields (`success`, `error`, `tool_parameters`), and error context (`status_code`, `attempt`).
|
|
377
377
|
|
|
378
378
|
---
|
|
379
379
|
|
|
@@ -412,8 +412,8 @@ Z-scores are color-coded: green (|z| < 1.0), yellow (approaching threshold), red
|
|
|
412
412
|
|
|
413
413
|
## Packaging
|
|
414
414
|
|
|
415
|
-
- **PyPI package name:** `tokenjam`
|
|
416
|
-
- **CLI command:** `
|
|
417
|
-
- **Python package directory:** `
|
|
418
|
-
- **Build system:** hatchling, with `[tool.hatch.build.targets.wheel] packages = ["
|
|
415
|
+
- **PyPI package name:** `tokenjam`
|
|
416
|
+
- **CLI command:** `tj`
|
|
417
|
+
- **Python package directory:** `tokenjam/`
|
|
418
|
+
- **Build system:** hatchling, with `[tool.hatch.build.targets.wheel] packages = ["tokenjam"]`
|
|
419
419
|
- **npm package:** `@tokenjam/sdk` under `sdk-ts/`
|
|
@@ -10,7 +10,7 @@ tj status --agent claude-code-<project>
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
`tj onboard --claude-code` does everything in one shot:
|
|
13
|
-
- Creates a shared config at `~/.config/
|
|
13
|
+
- Creates a shared config at `~/.config/tj/config.toml` (one config for all your projects)
|
|
14
14
|
- Writes OTLP exporter vars to `~/.claude/settings.json` so Claude Code sends telemetry automatically
|
|
15
15
|
- Tags this project's sessions by writing `OTEL_RESOURCE_ATTRIBUTES=service.name=claude-code-<project>` to `.claude/settings.json`
|
|
16
16
|
- Registers the MCP server globally (`claude mcp add --scope user tj -- tj mcp`)
|
|
@@ -50,32 +50,32 @@ The MCP server is included in the `[mcp]` extra and registered automatically by
|
|
|
50
50
|
| `get_tool_stats` | Tool call counts and average duration |
|
|
51
51
|
| `get_drift_report` | Behavioral drift baseline vs latest session |
|
|
52
52
|
| `acknowledge_alert` | Mark an alert as acknowledged |
|
|
53
|
-
| `setup_project` | Configure a project to send telemetry to
|
|
53
|
+
| `setup_project` | Configure a project to send telemetry to TokenJam |
|
|
54
54
|
| `open_dashboard` | Open the web UI — starts `tj serve` on demand if needed |
|
|
55
55
|
|
|
56
56
|
The MCP server opens the DuckDB file read-only — no lock conflicts with `tj serve` if both are running. The single write operation (`acknowledge_alert`) opens a short-lived read-write connection only for its UPDATE.
|
|
57
57
|
|
|
58
58
|
**Per-project telemetry tagging** — after installing the MCP server globally, ask Claude Code to set up each project:
|
|
59
59
|
|
|
60
|
-
> "Set up
|
|
60
|
+
> "Set up TokenJam for this project"
|
|
61
61
|
|
|
62
62
|
Claude calls `setup_project`, which writes `.claude/settings.json` with `OTEL_RESOURCE_ATTRIBUTES=service.name=<project>` so spans from that project are tagged with the right agent ID.
|
|
63
63
|
|
|
64
64
|
## Uninstalling
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
# Remove all
|
|
67
|
+
# Remove all TokenJam data, config, daemon, MCP registration, and env vars from every onboarded project:
|
|
68
68
|
tj uninstall --yes
|
|
69
69
|
|
|
70
|
-
# Then remove the package itself (
|
|
70
|
+
# Then remove the package itself (tj uninstall intentionally skips this):
|
|
71
71
|
pip uninstall tokenjam -y
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
`tj uninstall` cleans up everything set by `tj onboard --claude-code`:
|
|
75
75
|
- Stops and removes the background daemon (launchd/systemd)
|
|
76
76
|
- Deregisters the MCP server from Claude Code
|
|
77
|
-
- Deletes `~/.
|
|
78
|
-
- Deletes `~/.config/
|
|
77
|
+
- Deletes `~/.tj/` (telemetry database)
|
|
78
|
+
- Deletes `~/.config/tj/` (global config and projects index)
|
|
79
79
|
- Removes OTLP env vars from `~/.claude/settings.json`
|
|
80
80
|
- Removes `OTEL_RESOURCE_ATTRIBUTES` from `.claude/settings.json` in every onboarded project
|
|
81
81
|
- Removes the harness env block from `~/.zshrc`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`tj` uses TOML configuration. Run `tj onboard` to generate a starter config, or create one manually.
|
|
4
4
|
|
|
5
5
|
## Config file discovery
|
|
6
6
|
|
|
@@ -45,11 +45,11 @@ completions = false
|
|
|
45
45
|
tool_outputs = false
|
|
46
46
|
|
|
47
47
|
[storage]
|
|
48
|
-
path = "~/.
|
|
48
|
+
path = "~/.tj/telemetry.duckdb"
|
|
49
49
|
retention_days = 90
|
|
50
50
|
|
|
51
51
|
[security]
|
|
52
|
-
ingest_secret = "
|
|
52
|
+
ingest_secret = "..." # generated by tj onboard
|
|
53
53
|
|
|
54
54
|
[api]
|
|
55
55
|
host = "127.0.0.1"
|
|
@@ -90,7 +90,7 @@ Set limits via CLI (`tj budget --daily 10`), the REST API (`POST /api/v1/budget`
|
|
|
90
90
|
|
|
91
91
|
## Capture settings
|
|
92
92
|
|
|
93
|
-
By default, `
|
|
93
|
+
By default, `tj` does not capture prompt content, completion content, or tool outputs. Enable these selectively if you need them for debugging or evaluation:
|
|
94
94
|
|
|
95
95
|
```toml
|
|
96
96
|
[capture]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Export and Integrate
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`tj` stores all telemetry in a local DuckDB database. Export it in multiple formats for analysis, evaluation, or forwarding to external backends.
|
|
4
4
|
|
|
5
5
|
## Export formats
|
|
6
6
|
|