argus-code 0.4.2__tar.gz → 0.4.4__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.
- argus_code-0.4.4/AGENTS.md +119 -0
- argus_code-0.4.4/CLAUDE.md +14 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/PKG-INFO +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/SECURITY.md +22 -7
- argus_code-0.4.4/dashboard/AGENTS.md +35 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/session.astro +11 -2
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/settings.astro +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/tools.astro +5 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/charts.36uaSAWt.js +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/format.BexCUztC.js +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.BF0nZzma.js +11 -11
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.D-QKQJAF.js +24 -24
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/models.astro_astro_type_script_index_0_lang.0Aczy7Vm.js +13 -13
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/prompts.astro_astro_type_script_index_0_lang.B1i5N4zM.js +17 -17
- argus_code-0.4.4/dashboard-dist/_astro/session.CGJ-XRoC.css +1 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/session.astro_astro_type_script_index_0_lang.SRsknMTL.js +126 -126
- argus_code-0.4.2/dashboard-dist/_astro/settings.astro_astro_type_script_index_0_lang.BLXx3usF.js → argus_code-0.4.4/dashboard-dist/_astro/settings.astro_astro_type_script_index_0_lang.DyHh8NQi.js +24 -24
- argus_code-0.4.4/dashboard-dist/_astro/tools.astro_astro_type_script_index_0_lang.DHTUv2RL.js +12 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/trends.astro_astro_type_script_index_0_lang.CBtUcxGK.js +5 -5
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/index.html +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/prompts/index.html +17 -17
- argus_code-0.4.4/dashboard-dist/session/index.html +1 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/settings/index.html +8 -8
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/tools/index.html +1 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/pyproject.toml +1 -1
- argus_code-0.4.4/python/argus/AGENTS.md +50 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/__init__.py +1 -1
- argus_code-0.4.4/python/argus/adapters/AGENTS.md +44 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/adapter.py +14 -3
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/discover.py +14 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/cli.py +41 -5
- argus_code-0.4.4/python/argus/collector/AGENTS.md +37 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/first_run.py +9 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/daemon/process.py +6 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/scaffold/scaffolder.py +29 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/scaffold/snapshot.py +42 -2
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/scaffold/storage.py +17 -1
- argus_code-0.4.4/python/argus/server/AGENTS.md +46 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/server/api.py +37 -13
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/server/app.py +58 -1
- argus_code-0.4.4/python/argus/store/AGENTS.md +43 -0
- argus_code-0.4.4/tests/AGENTS.md +35 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_discover.py +5 -5
- argus_code-0.4.4/tests/adapters/claude_code/test_path_containment.py +154 -0
- argus_code-0.4.4/tests/cli/test_indexing_cli.py +47 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_pipeline.py +61 -2
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/daemon/test_process.py +3 -1
- argus_code-0.4.4/tests/daemon/test_spawn_safe_path.py +64 -0
- argus_code-0.4.4/tests/dashboard/test_chart_tooltip_escaping.py +87 -0
- argus_code-0.4.4/tests/scaffold/test_scaffold_containment.py +157 -0
- argus_code-0.4.4/tests/scaffold/test_snapshot_secrets.py +103 -0
- argus_code-0.4.4/tests/server/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/server/test_api.py +11 -7
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/server/test_api_search.py +5 -1
- argus_code-0.4.4/tests/server/test_param_bounds.py +99 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/server/test_server.py +153 -6
- argus_code-0.4.4/tests/store/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/test_e2e.py +5 -1
- {argus_code-0.4.2 → argus_code-0.4.4}/uv.lock +983 -983
- argus_code-0.4.2/dashboard-dist/_astro/tools.astro_astro_type_script_index_0_lang.OvyHH6MH.js +0 -12
- argus_code-0.4.2/dashboard-dist/session/index.html +0 -2
- {argus_code-0.4.2 → argus_code-0.4.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/.github/pull_request_template.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/.gitignore +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/.npmrc +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/ARCHITECTURE.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/CONTRIBUTING.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/LICENSE +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/NOTICE +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/PRD.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/README.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/TESTING.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/.astro/content-assets.mjs +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/.astro/content-modules.mjs +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/.astro/content.d.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/.astro/types.d.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/astro.config.mjs +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/package-lock.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/package.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/public/styles/global.css +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/layouts/Default.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/index.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/models.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/prompts.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/sessions/index.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/pages/trends.astro +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/scripts/alerts.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/scripts/api.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/scripts/charts.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/scripts/format.ts +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/src/styles/global.css +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard/tsconfig.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/_astro/installCanvasRenderer.XK5yP7fW.js +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/models/index.html +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/sessions/index.html +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/styles/global.css +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/dashboard-dist/trends/index.html +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/pricing/2026-05-02.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/pricing/2026-06-12.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/base.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/extract_tool_calls.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/extract_transcript.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/extract_turns.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/history_jsonl.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/ingest_file.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/model.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/claude_code/schemas.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/adapters/registry.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/aggregate.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/pipeline.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/rollup_subagents.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/scheduler.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/search_backfill.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/collector/watcher.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/core/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/core/runtime.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/daemon/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/daemon/logging.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/daemon/pidfile.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/daemon/service.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/detectors/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/detectors/base.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/detectors/registry.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/detectors/tool_error_rate_spike.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/pricing/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/pricing/compute.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/pricing/load.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/pricing/refresh.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/pricing/types.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/scaffold/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/schema/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/schema/types.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/server/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/store/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/store/db.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/store/migrations/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/store/migrations/inline.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/python/argus/store/repository.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/agents/code-reviewer.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/agents/security-auditor.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/commands/commit.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/commands/deploy.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/commands/fix-issue.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/commands/pr.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/commands/review.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/rules/api-conventions.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/rules/code-style.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/rules/testing.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/settings.json +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/.claude/skills/example/SKILL.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/templates/default/CLAUDE.md +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_adapter.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_extract_tool_calls.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_extract_transcript.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_extract_turns.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_history_jsonl.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_ingest_file.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_integration.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_model.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/claude_code/test_schemas.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/adapters/test_registry.py +0 -0
- {argus_code-0.4.2/tests/collector → argus_code-0.4.4/tests/cli}/__init__.py +0 -0
- {argus_code-0.4.2/tests/core → argus_code-0.4.4/tests/collector}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_aggregate.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_first_run.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_rollup_subagents.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_scheduler.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/collector/test_watcher.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/conftest.py +0 -0
- {argus_code-0.4.2/tests/daemon → argus_code-0.4.4/tests/core}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/core/test_runtime.py +0 -0
- {argus_code-0.4.2/tests/detectors → argus_code-0.4.4/tests/daemon}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/daemon/test_logs.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/daemon/test_pidfile.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/daemon/test_service.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/daemon/test_yield.py +0 -0
- {argus_code-0.4.2/tests/pricing → argus_code-0.4.4/tests/dashboard}/__init__.py +0 -0
- {argus_code-0.4.2/tests/scaffold → argus_code-0.4.4/tests/detectors}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/detectors/test_registry.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/detectors/test_tool_error_rate_spike.py +0 -0
- {argus_code-0.4.2/tests/schema → argus_code-0.4.4/tests/pricing}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/pricing/test_compute.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/pricing/test_load.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/pricing/test_refresh.py +0 -0
- {argus_code-0.4.2/tests/server → argus_code-0.4.4/tests/scaffold}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/scaffold/test_bundled_template.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/scaffold/test_cli_claude.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/scaffold/test_scaffolder.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/scaffold/test_snapshot.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/scaffold/test_storage.py +0 -0
- {argus_code-0.4.2/tests/store → argus_code-0.4.4/tests/schema}/__init__.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/schema/test_types.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/server/test_week_of.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/store/test_db.py +0 -0
- {argus_code-0.4.2 → argus_code-0.4.4}/tests/store/test_repository.py +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# AGENTS.md — Argus (argus-code) root work contract
|
|
2
|
+
|
|
3
|
+
> This repository uses the **DOX framework**: AGENTS.md files are binding work
|
|
4
|
+
> contracts for their subtree. Before editing any path, read this file and every
|
|
5
|
+
> AGENTS.md on the route from the repo root down to that path. The nearest doc
|
|
6
|
+
> controls local detail; this root controls repo-wide rules. No child doc may
|
|
7
|
+
> weaken DOX. Re-read the chain in-session; do not rely on memory.
|
|
8
|
+
>
|
|
9
|
+
> **After a meaningful change, run the DOX pass:** update the nearest owning
|
|
10
|
+
> AGENTS.md (and any affected parent/child index) when you change purpose, scope,
|
|
11
|
+
> contracts, workflows, inputs/outputs, or the doc tree itself; delete stale text;
|
|
12
|
+
> then re-check changed paths against the chain. Pure no-behavior edits may leave
|
|
13
|
+
> docs unchanged, but the pass still happens.
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Argus is a **local-first** analytics dashboard for Claude Code (and other coding
|
|
18
|
+
agents). A watcher ingests Claude Code's `.jsonl` session transcripts into a local
|
|
19
|
+
SQLite archive (`~/.argus/argus.db`); a FastAPI server serves a static Astro
|
|
20
|
+
dashboard at `http://localhost:4242`. No network, no telemetry, no LLM calls
|
|
21
|
+
(except opt-in `argus pricing refresh`). Backend + dashboard ship together in the
|
|
22
|
+
`argus-code` wheel on PyPI.
|
|
23
|
+
|
|
24
|
+
Orientation docs (prose, not contracts — read but don't duplicate into AGENTS.md):
|
|
25
|
+
- `ARCHITECTURE.md` — how the pieces fit together (read before adding a feature).
|
|
26
|
+
- `CONTRIBUTING.md` — dev quick start (`uv sync`, `uv run argus start`).
|
|
27
|
+
- `TESTING.md` — test catalog and conventions.
|
|
28
|
+
|
|
29
|
+
## Ownership
|
|
30
|
+
|
|
31
|
+
This root owns: the development workflow below, global engineering rules, the
|
|
32
|
+
release process, and the top-level Child DOX Index. Code-level contracts live in
|
|
33
|
+
the nearest child AGENTS.md.
|
|
34
|
+
|
|
35
|
+
## Local Contracts
|
|
36
|
+
|
|
37
|
+
### Development workflow (feature / bug → PR → merge → release → tag → publish)
|
|
38
|
+
|
|
39
|
+
Follow this end-to-end for every feature or bug fix.
|
|
40
|
+
|
|
41
|
+
1. **Branch.** Never commit feature/bug work directly to `main`. Branch from an
|
|
42
|
+
up-to-date `main`: `fix/<slug>` for bugs, `feat/<slug>` for features.
|
|
43
|
+
2. **Implement test-first.** Reproduce the bug (or specify the feature) with a
|
|
44
|
+
failing test, then make it pass. See `tests/AGENTS.md`.
|
|
45
|
+
3. **Commit** in small, logical units. Conventional-commit subjects
|
|
46
|
+
(`fix:`, `feat:`, `test:`, `release:`, `docs:`). End every commit message with:
|
|
47
|
+
```
|
|
48
|
+
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
49
|
+
```
|
|
50
|
+
4. **Verify** before opening the PR — see Verification below. Tests must be green
|
|
51
|
+
(the one known Windows flake is the scheduler timing test; confirm it passes in
|
|
52
|
+
isolation).
|
|
53
|
+
5. **Push & open PR** against `main`: `gh pr create --base main --head <branch>`.
|
|
54
|
+
End the PR body with:
|
|
55
|
+
```
|
|
56
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
57
|
+
```
|
|
58
|
+
6. **Merge** with squash and delete the branch:
|
|
59
|
+
`gh pr merge <n> --squash --delete-branch`. Then sync local `main`.
|
|
60
|
+
7. **Release** (only when cutting a version — see Release process below).
|
|
61
|
+
8. **Tag + GitHub release:** `gh release create vX.Y.Z --target main --title vX.Y.Z --notes "..."`.
|
|
62
|
+
9. **PyPI publish is the maintainer's manual step** — see Release process.
|
|
63
|
+
|
|
64
|
+
### Release process (manual — no CI release, no stored credentials)
|
|
65
|
+
|
|
66
|
+
When cutting version `X.Y.Z`:
|
|
67
|
+
1. Bump the version in **both** files with the Edit tool (not PowerShell
|
|
68
|
+
`Set-Content` — it injects a BOM): `pyproject.toml` (`version = "X.Y.Z"`) and
|
|
69
|
+
`python/argus/__init__.py` (`__version__ = "X.Y.Z"`).
|
|
70
|
+
2. `uv lock` to sync `uv.lock` to the new version.
|
|
71
|
+
3. If the dashboard changed, rebuild and refresh the shipped copy — see
|
|
72
|
+
`dashboard/AGENTS.md`.
|
|
73
|
+
4. Clean-build the artifacts: **`rm -rf dist && uv build`** (always clear `dist/`
|
|
74
|
+
first, or stale files get uploaded).
|
|
75
|
+
5. Confirm the wheel ships the right version + dashboard before publishing.
|
|
76
|
+
6. Tag + GitHub release (workflow step 8).
|
|
77
|
+
7. **Publish to PyPI — maintainer only:** `uv publish --token pypi-<token>`. The
|
|
78
|
+
token is the maintainer's secret; **an agent must never run this or handle the
|
|
79
|
+
token.** Stop and hand off.
|
|
80
|
+
|
|
81
|
+
## Work Guidance
|
|
82
|
+
|
|
83
|
+
Global engineering rules (binding):
|
|
84
|
+
- **Never destroy user data in `~/.argus/argus.db`.** Migrations must be
|
|
85
|
+
non-destructive, idempotent, and self-healing. See `python/argus/store/AGENTS.md`.
|
|
86
|
+
- **No hacks to make a test pass.** Fix the real cause, or correct a stale test
|
|
87
|
+
expectation to match the real contract (and say so). This is a prod package used
|
|
88
|
+
by many; never hardcode a value just to go green.
|
|
89
|
+
- **Backend runs from source** (`uv run argus start`) — no build step for Python.
|
|
90
|
+
Only the dashboard has a build step.
|
|
91
|
+
- Plans/specs under `docs/superpowers/` are scratch and gitignored — do not commit them.
|
|
92
|
+
|
|
93
|
+
## Verification
|
|
94
|
+
|
|
95
|
+
- Backend: `uv run pytest` (must be green; ~290 tests, ~25s on Windows).
|
|
96
|
+
- Dashboard: `cd dashboard && npm run build` (must succeed).
|
|
97
|
+
- Built form smoke test: see `CONTRIBUTING.md` "Running the built form".
|
|
98
|
+
|
|
99
|
+
## User Preferences
|
|
100
|
+
|
|
101
|
+
- Releases are cut deliberately by the maintainer; agents prepare everything up to
|
|
102
|
+
(and including the GitHub tag/release when asked) but never run `uv publish`.
|
|
103
|
+
- Prefer honest reporting over green-at-any-cost: surface flakes, skips, and
|
|
104
|
+
pre-existing failures explicitly.
|
|
105
|
+
|
|
106
|
+
## Child DOX Index
|
|
107
|
+
|
|
108
|
+
- `python/argus/AGENTS.md` — Python backend package; owns the subsystems without
|
|
109
|
+
their own doc (`core`, `daemon`, `detectors`, `pricing`, `scaffold`, `schema`)
|
|
110
|
+
and indexes the four below.
|
|
111
|
+
- `python/argus/store/AGENTS.md` — SQLite, migrations, repository; data-safety
|
|
112
|
+
and path-normalization contracts.
|
|
113
|
+
- `python/argus/collector/AGENTS.md` — ingest pipeline and the missing-data
|
|
114
|
+
backfill (incl. sub-agent segment re-read).
|
|
115
|
+
- `python/argus/adapters/AGENTS.md` — Claude Code adapter and transcript-segment
|
|
116
|
+
extraction; sub-agent file layout.
|
|
117
|
+
- `python/argus/server/AGENTS.md` — FastAPI routes, static serving, clean shutdown.
|
|
118
|
+
- `dashboard/AGENTS.md` — Astro dashboard and the `dashboard-dist` ship chain.
|
|
119
|
+
- `tests/AGENTS.md` — pytest conventions and platform quirks.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This repository uses the **DOX framework** — an `AGENTS.md` hierarchy of binding
|
|
4
|
+
work contracts. `AGENTS.md` (repo root) is the source of truth, including the full
|
|
5
|
+
development workflow (branch → PR → squash-merge → release → tag → publish).
|
|
6
|
+
|
|
7
|
+
**Before editing any path:** read the root `AGENTS.md`, then every `AGENTS.md` on
|
|
8
|
+
the route down to that path; the nearest doc controls local detail. **After a
|
|
9
|
+
meaningful change:** run the DOX closeout (update the nearest owning doc and any
|
|
10
|
+
affected parent/child indexes). Re-read the chain in-session — don't rely on memory.
|
|
11
|
+
|
|
12
|
+
The root contract (imported in full below):
|
|
13
|
+
|
|
14
|
+
@AGENTS.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: argus-code
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Local-first dashboard for Claude Code cost, token, tool-usage, and full-text search analytics
|
|
5
5
|
Project-URL: Homepage, https://github.com/KrishBhimani/argus-code
|
|
6
6
|
Project-URL: Repository, https://github.com/KrishBhimani/argus-code.git
|
|
@@ -33,8 +33,10 @@ Argus is built for one user, one machine. It assumes:
|
|
|
33
33
|
before rendering in the dashboard, and never executed.
|
|
34
34
|
- **Untrusted browsers visiting localhost.** Other webpages the user
|
|
35
35
|
loads while Argus is running are not trusted. They cannot read
|
|
36
|
-
Argus data (Same-Origin Policy on responses
|
|
37
|
-
|
|
36
|
+
Argus data (Same-Origin Policy on responses, backed by a loopback
|
|
37
|
+
`Host` allowlist so DNS rebinding can't turn a hostile domain into
|
|
38
|
+
a same-origin one) and cannot trigger state changes (CSRF Origin
|
|
39
|
+
check on POST).
|
|
38
40
|
|
|
39
41
|
## Defaults that matter
|
|
40
42
|
|
|
@@ -78,14 +80,23 @@ Things this codebase deliberately does to reduce attack surface:
|
|
|
78
80
|
`escapeHtml()` before reaching `innerHTML`. The only HTML allowed
|
|
79
81
|
through is `<mark>...</mark>` from FTS5 `snippet()`, applied via a
|
|
80
82
|
separate `safeSnippet()` helper that escapes everything else.
|
|
81
|
-
- `watchdog` does not follow symlinks by default.
|
|
82
|
-
|
|
83
|
-
and
|
|
84
|
-
`~/.claude/` tree.
|
|
83
|
+
- `watchdog` does not follow symlinks by default. Every read additionally
|
|
84
|
+
goes through `ClaudeCodeAdapter.ingest_file`, which calls
|
|
85
|
+
`Path.resolve(strict=True)` and refuses anything that doesn't
|
|
86
|
+
canonicalise under the `~/.claude/` tree — symlink or NTFS junction.
|
|
87
|
+
The check sits at that single choke point (not at each caller) so
|
|
88
|
+
discovery, the watcher, and the sub-agent walk are all covered by
|
|
89
|
+
construction; `sub_agent_files_for` filters as well.
|
|
85
90
|
- Per-tick read cap of 64 MiB on session JSONL and `history.jsonl`,
|
|
86
91
|
so a runaway or hostile multi-GB file can't OOM the process.
|
|
87
92
|
- CSRF Origin check on all non-GET API routes (FastAPI middleware in
|
|
88
93
|
`python/argus/server/app.py`).
|
|
94
|
+
- Loopback `Host` header allowlist on **every** route, static mount
|
|
95
|
+
included (`is_loopback_host` in `python/argus/server/app.py`). This is
|
|
96
|
+
what stops DNS rebinding: a page on `evil.com` that repoints its own
|
|
97
|
+
DNS at `127.0.0.1` still sends `Host: evil.com` and gets a 421, so it
|
|
98
|
+
never reaches the GET routes the Origin check deliberately exempts.
|
|
99
|
+
Skipped only under `--host 0.0.0.0`, which is already a warned opt-out.
|
|
89
100
|
- No build hooks running on user machines. The wheel ships pure Python
|
|
90
101
|
+ bundled data (`dashboard-dist/`, `pricing/`, `templates/`).
|
|
91
102
|
Installation runs no arbitrary code.
|
|
@@ -95,7 +106,11 @@ Things this codebase deliberately does to reduce attack surface:
|
|
|
95
106
|
- `argus claude` scaffolding is a pure file copy — no templating,
|
|
96
107
|
substitution, or code execution. It writes only to the path you hand
|
|
97
108
|
`init` (created if absent) or under `~/.argus/templates/`, and never
|
|
98
|
-
overwrites an existing `CLAUDE.md`.
|
|
109
|
+
overwrites an existing `CLAUDE.md`. That containment is enforced, not
|
|
110
|
+
just intended: every destination must canonicalise under the target
|
|
111
|
+
directory, so a hostile repo shipping `.claude/` as a symlink or NTFS
|
|
112
|
+
junction can't redirect the write, and template names are validated as
|
|
113
|
+
plain directory names so `--template ../../x` can't escape the store.
|
|
99
114
|
|
|
100
115
|
If you spot a regression on any of the above, that's a real bug and
|
|
101
116
|
worth reporting.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# AGENTS.md — dashboard (Astro frontend + ship chain)
|
|
2
|
+
|
|
3
|
+
Parent: repo-root `AGENTS.md`. The statically-built UI served by `server/`.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Astro + ECharts dashboard. Source pages live in `src/pages/*.astro`
|
|
8
|
+
(`session.astro`, `settings.astro`, `overview`, `timeline`, …) with shared
|
|
9
|
+
scripts in `src/scripts/`.
|
|
10
|
+
|
|
11
|
+
## Local Contracts
|
|
12
|
+
|
|
13
|
+
- **Three "dist" directories — don't conflate them:**
|
|
14
|
+
- `dashboard/dist/` — raw Astro build output. **Gitignored.**
|
|
15
|
+
- `dashboard-dist/` (repo root) — the **tracked** copy that ships in the wheel
|
|
16
|
+
via `pyproject.toml` force-include (`"dashboard-dist" = "argus/dashboard-dist"`).
|
|
17
|
+
- `dist/` (repo root) — `uv build` output uploaded to PyPI. **Gitignored.**
|
|
18
|
+
- **A dashboard source edit is invisible to the package until `dashboard-dist` is
|
|
19
|
+
refreshed and committed.** After changing anything under `dashboard/src/`:
|
|
20
|
+
```sh
|
|
21
|
+
cd dashboard && npm run build && cd ..
|
|
22
|
+
git rm -r --quiet dashboard-dist && cp -r dashboard/dist dashboard-dist && git add -A dashboard-dist
|
|
23
|
+
```
|
|
24
|
+
Commit the rebuilt `dashboard-dist` alongside the source change. Astro filenames
|
|
25
|
+
are content-hashed, so a real change shows as new `_astro/*.js|css` plus updated
|
|
26
|
+
`*/index.html` — verify the new asset (and absence of stale strings) in
|
|
27
|
+
`dashboard-dist` before committing.
|
|
28
|
+
- Avoid em dashes / non-ASCII in strings that surface in the **terminal**
|
|
29
|
+
(CLI/console) — they mojibake on the Windows console. (UI text is fine.)
|
|
30
|
+
|
|
31
|
+
## Verification
|
|
32
|
+
|
|
33
|
+
`cd dashboard && npm run build` must succeed. After refreshing `dashboard-dist`,
|
|
34
|
+
optionally confirm the wheel ships it (`rm -rf dist && uv build`, then inspect the
|
|
35
|
+
`.whl`).
|
|
@@ -119,7 +119,16 @@ import Default from '../layouts/Default.astro';
|
|
|
119
119
|
}
|
|
120
120
|
#to-top:hover { color: var(--text-0); border-color: var(--accent, #f0883e); }
|
|
121
121
|
.sa-wrap { display: grid; grid-template-columns: 38% 62%; gap: 1rem; align-items: start; }
|
|
122
|
-
.sa-list {
|
|
122
|
+
.sa-list {
|
|
123
|
+
display: flex; flex-direction: column; gap: 2px;
|
|
124
|
+
max-height: calc(100vh - 13rem); overflow-y: auto;
|
|
125
|
+
padding-right: 0.35rem; scrollbar-gutter: stable;
|
|
126
|
+
scrollbar-width: thin; scrollbar-color: var(--border) transparent;
|
|
127
|
+
}
|
|
128
|
+
.sa-list::-webkit-scrollbar { width: 8px; }
|
|
129
|
+
.sa-list::-webkit-scrollbar-track { background: transparent; }
|
|
130
|
+
.sa-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
|
|
131
|
+
.sa-list::-webkit-scrollbar-thumb:hover { background: var(--text-2); }
|
|
123
132
|
.sa-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.55rem; border-radius: 7px; cursor: pointer; font-size: 0.84rem; }
|
|
124
133
|
.sa-row:hover { background: var(--bg-2); }
|
|
125
134
|
.sa-row.sel { background: var(--bg-2); box-shadow: inset 0 0 0 1px var(--border); }
|
|
@@ -127,7 +136,7 @@ import Default from '../layouts/Default.astro';
|
|
|
127
136
|
.sa-dot.ok { color: var(--good); }
|
|
128
137
|
.sa-dot.error { color: #f85149; }
|
|
129
138
|
.sa-meta { margin-left: auto; color: var(--text-2); font-size: 0.76rem; white-space: nowrap; }
|
|
130
|
-
.sa-detail { padding: 1rem; }
|
|
139
|
+
.sa-detail { padding: 1rem; position: sticky; top: 1rem; align-self: start; }
|
|
131
140
|
.sa-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-bottom: 0.8rem; }
|
|
132
141
|
.sa-stats > div { background: var(--bg-2); border-radius: 8px; padding: 0.5rem 0.6rem; }
|
|
133
142
|
.sa-stats span { display: block; color: var(--text-2); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; }
|
|
@@ -219,7 +219,7 @@ import Default from '../layouts/Default.astro';
|
|
|
219
219
|
daemon = (await fetch('/api/ingest/status').then(r => r.json())).daemon === true;
|
|
220
220
|
} catch { /* leave daemon=false */ }
|
|
221
221
|
if (daemon) {
|
|
222
|
-
actions.innerHTML = `<span style="color:var(--text-2);font-size:0.82rem;">Read-only while <code>argusd</code> is running — manage indexing from the CLI (<code>argus
|
|
222
|
+
actions.innerHTML = `<span style="color:var(--text-2);font-size:0.82rem;">Read-only while <code>argusd</code> is running — manage indexing from the CLI (<code>argus indexing enable</code>) or stop the daemon with <code>argus daemon stop</code>.</span>`;
|
|
223
223
|
return;
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -72,7 +72,11 @@ import Default from '../layouts/Default.astro';
|
|
|
72
72
|
const i = p[0].dataIndex;
|
|
73
73
|
const calls = values[i];
|
|
74
74
|
const err = errors?.[i] ?? 0;
|
|
75
|
-
return
|
|
75
|
+
// ECharts renders a custom tooltip formatter's return value as
|
|
76
|
+
// HTML, so the label -- a tool / MCP-server / sub-agent name read
|
|
77
|
+
// verbatim from .jsonl -- must be escaped here too, exactly like
|
|
78
|
+
// every other innerHTML sink on this page.
|
|
79
|
+
return `${escapeHtml(labels[i])}<br>Calls: ${calls.toLocaleString()}` +
|
|
76
80
|
(err ? `<br>Errors: ${err.toLocaleString()} (${((err/calls)*100).toFixed(1)}%)` : '');
|
|
77
81
|
},
|
|
78
82
|
},
|