Full Code of alinaqi/claude-bootstrap for AI

main 57c5c839f18f cached
501 files
2.7 MB
735.9k tokens
2970 symbols
1 requests
Download .txt
Showing preview only (3,021K chars total). Download the full file or copy to clipboard to get everything.
Repository: alinaqi/claude-bootstrap
Branch: main
Commit: 57c5c839f18f
Files: 501
Total size: 2.7 MB

Directory structure:
gitextract_idptty0p/

├── .github/
│   └── workflows/
│       ├── skill-lint.yml
│       └── skill-review.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── _project_specs/
│   ├── 00-autonomous-engineering-roadmap.md
│   ├── 01-runtime-observability.md
│   ├── 02-rollback-and-recovery.md
│   ├── 03-verifiable-contracts.md
│   ├── 04-multi-agent-coordination.md
│   ├── 05-confidence-calibration.md
│   ├── 06-cost-budget-awareness.md
│   ├── 07-human-escalation-protocol.md
│   ├── 08-auto-code-index.md
│   └── 09-multimodal-ingestion.md
├── commands/
│   ├── analyze-repo.md
│   ├── analyze-workspace.md
│   ├── check-contributors.md
│   ├── icpg-bootstrap.md
│   ├── icpg-drift.md
│   ├── icpg-impact.md
│   ├── icpg-why.md
│   ├── initialize-project.md
│   ├── maggy-init.md
│   ├── maggy.md
│   ├── mnemos-checkpoint.md
│   ├── mnemos-status.md
│   ├── polyphony-init.md
│   ├── polyphony-spawn.md
│   ├── polyphony-status.md
│   ├── spawn-team.md
│   ├── sync-agents.md
│   ├── sync-contracts.md
│   └── update-code-index.md
├── docs/
│   ├── architecture-v5.md
│   ├── benchmark-results.md
│   ├── mnemos-implementation.md
│   └── polyphony-spec.md
├── evals/
│   ├── README.md
│   ├── agent-teams/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── base/
│   │   ├── scenario-1/
│   │   │   ├── criteria.json
│   │   │   └── task.md
│   │   └── scenario-2/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── code-review/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── commit-hygiene/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── credentials/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── database-schema/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── existing-repo/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── llm-patterns/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── project-tooling/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── python/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── react-web/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── run-evals.sh
│   ├── security/
│   │   ├── scenario-1/
│   │   │   ├── criteria.json
│   │   │   └── task.md
│   │   └── scenario-2/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── session-management/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── supabase/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   └── typescript/
│       └── scenario-1/
│           ├── criteria.json
│           └── task.md
├── hooks/
│   ├── post-commit-graph
│   ├── pre-push
│   └── workspace/
│       ├── check-contract-freshness.sh
│       ├── check-graph-freshness.sh
│       ├── post-commit-contracts.sh
│       └── pre-push-contracts.sh
├── install.sh
├── maggy/
│   ├── .gitignore
│   ├── PLAN.md
│   ├── README.md
│   ├── config.example.yaml
│   ├── docs/
│   │   ├── benchmark-results.md
│   │   └── maggy-rfc.md
│   ├── install.sh
│   ├── maggy/
│   │   ├── __init__.py
│   │   ├── adapters/
│   │   │   ├── __init__.py
│   │   │   ├── cli_discovery.py
│   │   │   └── pi.py
│   │   ├── api/
│   │   │   ├── __init__.py
│   │   │   ├── auth.py
│   │   │   ├── routes.py
│   │   │   ├── routes_budget.py
│   │   │   ├── routes_chat.py
│   │   │   ├── routes_cikg.py
│   │   │   ├── routes_deploy.py
│   │   │   ├── routes_engram.py
│   │   │   ├── routes_escalation.py
│   │   │   ├── routes_events.py
│   │   │   ├── routes_forge.py
│   │   │   ├── routes_heartbeat.py
│   │   │   ├── routes_history.py
│   │   │   ├── routes_improve.py
│   │   │   ├── routes_lexon.py
│   │   │   ├── routes_mesh.py
│   │   │   ├── routes_mesh_admin.py
│   │   │   ├── routes_monitor.py
│   │   │   ├── routes_observability.py
│   │   │   ├── routes_planning.py
│   │   │   ├── routes_process.py
│   │   │   ├── routes_projects.py
│   │   │   ├── routes_routing.py
│   │   │   └── routes_setup.py
│   │   ├── budget.py
│   │   ├── calibration/
│   │   │   ├── __init__.py
│   │   │   └── tracker.py
│   │   ├── checkpoint.py
│   │   ├── cikg/
│   │   │   ├── __init__.py
│   │   │   ├── graph.py
│   │   │   ├── models.py
│   │   │   ├── queries.py
│   │   │   └── storage.py
│   │   ├── cli.py
│   │   ├── cli_chat.py
│   │   ├── cli_client.py
│   │   ├── cli_output.py
│   │   ├── cli_repl_cmds.py
│   │   ├── cli_sessions.py
│   │   ├── cli_welcome.py
│   │   ├── config.py
│   │   ├── contracts/
│   │   │   ├── __init__.py
│   │   │   └── generator.py
│   │   ├── coordination/
│   │   │   ├── __init__.py
│   │   │   └── lock_manager.py
│   │   ├── deploy.py
│   │   ├── discovery.py
│   │   ├── engram/
│   │   │   ├── __init__.py
│   │   │   ├── diagnostics.py
│   │   │   ├── record.py
│   │   │   ├── retrieval.py
│   │   │   ├── seed.py
│   │   │   └── store.py
│   │   ├── escalation/
│   │   │   ├── __init__.py
│   │   │   └── protocol.py
│   │   ├── event_spine/
│   │   │   ├── __init__.py
│   │   │   ├── emitter.py
│   │   │   ├── events.py
│   │   │   ├── header.py
│   │   │   └── store.py
│   │   ├── fatigue.py
│   │   ├── forge/
│   │   │   ├── __init__.py
│   │   │   ├── connector.py
│   │   │   ├── detector.py
│   │   │   └── registry.py
│   │   ├── heartbeat/
│   │   │   ├── __init__.py
│   │   │   ├── jobs.py
│   │   │   └── scheduler.py
│   │   ├── history/
│   │   │   ├── __init__.py
│   │   │   ├── analyzer.py
│   │   │   ├── models.py
│   │   │   ├── parsers/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── claude.py
│   │   │   │   ├── codex.py
│   │   │   │   └── kimi.py
│   │   │   ├── service.py
│   │   │   └── store.py
│   │   ├── improve/
│   │   │   ├── __init__.py
│   │   │   ├── analyzer.py
│   │   │   ├── models.py
│   │   │   ├── service.py
│   │   │   └── signals.py
│   │   ├── lexon/
│   │   │   ├── __init__.py
│   │   │   ├── disambiguate.py
│   │   │   ├── personalization.py
│   │   │   ├── record.py
│   │   │   ├── router.py
│   │   │   └── terminology.py
│   │   ├── main.py
│   │   ├── mesh/
│   │   │   ├── __init__.py
│   │   │   ├── discovery.py
│   │   │   ├── git_discovery.py
│   │   │   ├── manager.py
│   │   │   ├── memory.py
│   │   │   ├── network.py
│   │   │   ├── org_scanner.py
│   │   │   ├── protocol.py
│   │   │   ├── provenance.py
│   │   │   ├── publisher.py
│   │   │   ├── quarantine.py
│   │   │   ├── store.py
│   │   │   ├── sync.py
│   │   │   ├── transport.py
│   │   │   ├── ws_client.py
│   │   │   └── ws_server.py
│   │   ├── mnemos/
│   │   │   ├── __init__.py
│   │   │   ├── fatigue.py
│   │   │   └── signals.py
│   │   ├── models/
│   │   │   ├── __init__.py
│   │   │   └── plan.py
│   │   ├── observability/
│   │   │   ├── __init__.py
│   │   │   └── collector.py
│   │   ├── planning.py
│   │   ├── process/
│   │   │   ├── __init__.py
│   │   │   ├── discovery.py
│   │   │   ├── github_prs.py
│   │   │   ├── model_router.py
│   │   │   ├── models.py
│   │   │   ├── patterns.py
│   │   │   ├── report.py
│   │   │   ├── service.py
│   │   │   ├── signals.py
│   │   │   └── store.py
│   │   ├── providers/
│   │   │   ├── __init__.py
│   │   │   ├── asana.py
│   │   │   ├── base.py
│   │   │   ├── github_issues.py
│   │   │   └── monday.py
│   │   ├── recovery/
│   │   │   ├── __init__.py
│   │   │   └── rollback.py
│   │   ├── registry.py
│   │   ├── routing.py
│   │   ├── routing_rules.py
│   │   ├── routing_rules_defaults.py
│   │   ├── routing_rules_io.py
│   │   ├── scores.py
│   │   ├── services/
│   │   │   ├── __init__.py
│   │   │   ├── account_guide.py
│   │   │   ├── activity.py
│   │   │   ├── ai_client.py
│   │   │   ├── cascade.py
│   │   │   ├── chat.py
│   │   │   ├── chat_context.py
│   │   │   ├── chat_router.py
│   │   │   ├── chat_stream.py
│   │   │   ├── checkpoint.py
│   │   │   ├── competitor.py
│   │   │   ├── context_compactor.py
│   │   │   ├── convention_inferrer.py
│   │   │   ├── convention_scanner.py
│   │   │   ├── executor.py
│   │   │   ├── executor_helpers.py
│   │   │   ├── executor_prompts.py
│   │   │   ├── executor_types.py
│   │   │   ├── inbox.py
│   │   │   ├── monitor.py
│   │   │   ├── output_reviewer.py
│   │   │   ├── planner.py
│   │   │   ├── session_detect.py
│   │   │   ├── stakes.py
│   │   │   ├── tdd_verifier.py
│   │   │   └── vision.py
│   │   └── static/
│   │       ├── app.js
│   │       └── index.html
│   ├── pyproject.toml
│   └── tests/
│       ├── conftest.py
│       ├── integration/
│       │   ├── __init__.py
│       │   ├── test_full_task_flow.py
│       │   ├── test_model_fallback.py
│       │   └── test_process_loop.py
│       ├── test_account_guide.py
│       ├── test_activity.py
│       ├── test_api_endpoints.py
│       ├── test_benchmark_scenario.py
│       ├── test_bootstrap.py
│       ├── test_budget.py
│       ├── test_calibration.py
│       ├── test_cascade.py
│       ├── test_chat.py
│       ├── test_chat_context.py
│       ├── test_chat_routed.py
│       ├── test_chat_router.py
│       ├── test_chat_stream.py
│       ├── test_checkpoint.py
│       ├── test_checkpoint_mgr.py
│       ├── test_cikg.py
│       ├── test_cli.py
│       ├── test_cli_chat.py
│       ├── test_cli_discovery.py
│       ├── test_cli_sessions.py
│       ├── test_cli_welcome.py
│       ├── test_context_compactor.py
│       ├── test_contracts.py
│       ├── test_convention_inferrer.py
│       ├── test_convention_scanner.py
│       ├── test_coordination.py
│       ├── test_deploy.py
│       ├── test_discovery.py
│       ├── test_dual_planner.py
│       ├── test_engram.py
│       ├── test_escalation.py
│       ├── test_event_spine.py
│       ├── test_executor_routing.py
│       ├── test_fatigue.py
│       ├── test_forge.py
│       ├── test_heartbeat.py
│       ├── test_history.py
│       ├── test_history_parsers.py
│       ├── test_improve.py
│       ├── test_lexon.py
│       ├── test_mesh.py
│       ├── test_mesh_network.py
│       ├── test_mesh_store.py
│       ├── test_mesh_ws.py
│       ├── test_mnemos_fatigue.py
│       ├── test_monday_provider.py
│       ├── test_monitor.py
│       ├── test_multimodel_integration.py
│       ├── test_observability.py
│       ├── test_output_reviewer.py
│       ├── test_pi_adapter.py
│       ├── test_planning.py
│       ├── test_registry.py
│       ├── test_repl_cmds.py
│       ├── test_rollback.py
│       ├── test_routes_escalation.py
│       ├── test_routes_observability.py
│       ├── test_routes_projects.py
│       ├── test_routing_config.py
│       ├── test_routing_rules.py
│       ├── test_routing_service.py
│       ├── test_scores.py
│       ├── test_setup_routes.py
│       ├── test_stakes.py
│       ├── test_tdd_verifier.py
│       ├── test_vision.py
│       └── test_zero_config.py
├── rules/
│   ├── nodejs-backend.md
│   ├── python.md
│   ├── quality-gates.md
│   ├── react.md
│   ├── security.md
│   ├── tdd-workflow.md
│   └── typescript.md
├── scripts/
│   ├── convert-hooks-to-toml.sh
│   ├── convert-skills-structure.sh
│   ├── detect-agents.sh
│   ├── icpg/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── bootstrap.py
│   │   ├── contracts.py
│   │   ├── drift.py
│   │   ├── models.py
│   │   ├── pyproject.toml
│   │   ├── store.py
│   │   ├── symbols.py
│   │   └── vectors.py
│   ├── install-graph-tools.sh
│   ├── install-hooks.sh
│   ├── install-skills.sh
│   ├── mnemos/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── checkpoint.py
│   │   ├── consolidation.py
│   │   ├── fatigue.py
│   │   ├── models.py
│   │   ├── pyproject.toml
│   │   ├── signals.py
│   │   └── store.py
│   ├── polyphony/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── adapters/
│   │   │   ├── __init__.py
│   │   │   ├── claude.py
│   │   │   ├── codex.py
│   │   │   └── kimi.py
│   │   ├── config.py
│   │   ├── events.py
│   │   ├── identity.py
│   │   ├── models.py
│   │   ├── orchestrator.py
│   │   ├── pyproject.toml
│   │   ├── router.py
│   │   ├── runtime.py
│   │   ├── scoring.py
│   │   ├── sources/
│   │   │   ├── __init__.py
│   │   │   ├── github.py
│   │   │   └── local.py
│   │   ├── state_machine.py
│   │   ├── store.py
│   │   └── workspace.py
│   └── skill_lint/
│       ├── __init__.py
│       ├── __main__.py
│       ├── content.py
│       ├── frontmatter.py
│       ├── pyproject.toml
│       ├── references.py
│       ├── report.py
│       └── spec.py
├── skills/
│   ├── aeo-optimization/
│   │   └── SKILL.md
│   ├── agent-teams/
│   │   ├── SKILL.md
│   │   └── agents/
│   │       ├── code-review.md
│   │       ├── feature.md
│   │       ├── merger.md
│   │       ├── quality.md
│   │       ├── security.md
│   │       └── team-lead.md
│   ├── agentic-development/
│   │   └── SKILL.md
│   ├── ai-models/
│   │   └── SKILL.md
│   ├── android-java/
│   │   └── SKILL.md
│   ├── android-kotlin/
│   │   └── SKILL.md
│   ├── aws-aurora/
│   │   └── SKILL.md
│   ├── aws-dynamodb/
│   │   └── SKILL.md
│   ├── azure-cosmosdb/
│   │   └── SKILL.md
│   ├── base/
│   │   └── SKILL.md
│   ├── cloudflare-d1/
│   │   └── SKILL.md
│   ├── code-deduplication/
│   │   └── SKILL.md
│   ├── code-graph/
│   │   └── SKILL.md
│   ├── code-review/
│   │   └── SKILL.md
│   ├── codex-review/
│   │   └── SKILL.md
│   ├── commit-hygiene/
│   │   └── SKILL.md
│   ├── cpg-analysis/
│   │   └── SKILL.md
│   ├── credentials/
│   │   └── SKILL.md
│   ├── cross-agent-delegation/
│   │   └── SKILL.md
│   ├── database-schema/
│   │   └── SKILL.md
│   ├── existing-repo/
│   │   └── SKILL.md
│   ├── firebase/
│   │   └── SKILL.md
│   ├── flutter/
│   │   └── SKILL.md
│   ├── gemini-review/
│   │   └── SKILL.md
│   ├── icpg/
│   │   └── SKILL.md
│   ├── iterative-development/
│   │   └── SKILL.md
│   ├── klaviyo/
│   │   └── SKILL.md
│   ├── llm-patterns/
│   │   └── SKILL.md
│   ├── maggy/
│   │   └── SKILL.md
│   ├── medusa/
│   │   └── SKILL.md
│   ├── mnemos/
│   │   └── SKILL.md
│   ├── ms-teams-apps/
│   │   └── SKILL.md
│   ├── nodejs-backend/
│   │   └── SKILL.md
│   ├── playwright-testing/
│   │   └── SKILL.md
│   ├── polyphony/
│   │   └── SKILL.md
│   ├── posthog-analytics/
│   │   └── SKILL.md
│   ├── project-tooling/
│   │   └── SKILL.md
│   ├── pwa-development/
│   │   └── SKILL.md
│   ├── python/
│   │   └── SKILL.md
│   ├── react-native/
│   │   └── SKILL.md
│   ├── react-web/
│   │   └── SKILL.md
│   ├── reddit-ads/
│   │   └── SKILL.md
│   ├── reddit-api/
│   │   └── SKILL.md
│   ├── security/
│   │   └── SKILL.md
│   ├── session-management/
│   │   └── SKILL.md
│   ├── shopify-apps/
│   │   └── SKILL.md
│   ├── site-architecture/
│   │   └── SKILL.md
│   ├── supabase/
│   │   └── SKILL.md
│   ├── supabase-nextjs/
│   │   └── SKILL.md
│   ├── supabase-node/
│   │   └── SKILL.md
│   ├── supabase-python/
│   │   └── SKILL.md
│   ├── team-coordination/
│   │   └── SKILL.md
│   ├── ticket-craft/
│   │   └── SKILL.md
│   ├── typescript/
│   │   └── SKILL.md
│   ├── ui-mobile/
│   │   └── SKILL.md
│   ├── ui-testing/
│   │   └── SKILL.md
│   ├── ui-web/
│   │   └── SKILL.md
│   ├── user-journeys/
│   │   └── SKILL.md
│   ├── web-content/
│   │   └── SKILL.md
│   ├── web-payments/
│   │   └── SKILL.md
│   ├── woocommerce/
│   │   └── SKILL.md
│   └── workspace/
│       └── SKILL.md
├── templates/
│   ├── AGENTS.md
│   ├── CLAUDE.local.md
│   ├── CLAUDE.md
│   ├── Dockerfile.polyphony
│   ├── codex-auto-review.sh
│   ├── config.toml
│   ├── icpg-pre-edit.sh
│   ├── icpg-stop-record.sh
│   ├── mnemos-post-compact-inject.sh
│   ├── mnemos-post-tool.sh
│   ├── mnemos-pre-compact.sh
│   ├── mnemos-pre-edit.sh
│   ├── mnemos-session-start.sh
│   ├── mnemos-statusline.sh
│   ├── mnemos-stop-checkpoint.sh
│   ├── polyphony-agents.yaml
│   ├── polyphony-config.yaml
│   ├── polyphony-identities.yaml
│   ├── polyphony-routing.yaml
│   ├── pre-compact.sh
│   ├── settings.json
│   └── tdd-loop-check.sh
└── tests/
    ├── test_cross_agent.py
    ├── test_cross_tool.py
    ├── test_polyphony_adapters.py
    ├── test_polyphony_config.py
    ├── test_polyphony_events.py
    ├── test_polyphony_identity.py
    ├── test_polyphony_models.py
    ├── test_polyphony_orchestrator.py
    ├── test_polyphony_router.py
    ├── test_polyphony_runtime.py
    ├── test_polyphony_scoring.py
    ├── test_polyphony_sources.py
    ├── test_polyphony_state.py
    ├── test_polyphony_store.py
    ├── test_polyphony_workspace.py
    ├── test_session_detect.py
    ├── test_skill_lint.py
    └── validate-structure.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/skill-lint.yml
================================================
name: Skill Lint

on:
  push:
    branches: [main]
    paths:
      - 'skills/**'
      - 'scripts/skill_lint/**'
      - 'tests/test_skill_lint.py'
  pull_request:
    paths:
      - 'skills/**'
      - 'scripts/skill_lint/**'
      - 'tests/test_skill_lint.py'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install pytest
        run: pip install pytest

      - name: Run skill-lint tests
        run: PYTHONPATH=scripts python -m pytest tests/test_skill_lint.py -v

      - name: Run skill-lint (errors fail)
        run: PYTHONPATH=scripts python -m skill_lint --fail-on error skills/

      - name: Run skill-lint (full report)
        if: always()
        run: PYTHONPATH=scripts python -m skill_lint --format json skills/ > skill-lint-report.json || true

      - name: Upload lint report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: skill-lint-report
          path: skill-lint-report.json


================================================
FILE: .github/workflows/skill-review.yml
================================================
name: Skill Review (Tessl + skills-ref)

on:
  pull_request:
    paths:
      - 'skills/**'

jobs:
  tessl:
    runs-on: ubuntu-latest
    if: ${{ vars.TESSL_ENABLED == 'true' }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Tessl
        uses: tesslio/setup-tessl@v2
        with:
          token: ${{ secrets.TESSL_TOKEN }}

      - name: Detect changed skills
        id: changes
        run: |
          # Multi-skill PRs produce a multi-line list. Plain echo "skills=$X"
          # fails GHA's output parser on newlines ("Invalid format"), AND the
          # downstream `for skill in ${{ outputs.skills }}` breaks on newlines
          # because the expansion ends the `for ... in` expression. Join with
          # spaces so both the output format and the shell loop are happy.
          CHANGED=$(git diff --name-only origin/main...HEAD -- skills/ | cut -d'/' -f2 | sort -u | tr '\n' ' ')
          # Trim trailing space for clean logs
          CHANGED="${CHANGED%% }"
          echo "skills=$CHANGED" >> "$GITHUB_OUTPUT"
          echo "Changed skills: $CHANGED"

      - name: Run Tessl review on changed skills
        if: steps.changes.outputs.skills != ''
        run: |
          for skill in ${{ steps.changes.outputs.skills }}; do
            echo "=== Reviewing: $skill ==="
            tessl skill lint "skills/$skill" || true
            tessl skill review --json "skills/$skill" || true
          done

  skills-ref:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install skills-ref
        run: pip install skills-ref || echo "skills-ref not available, skipping"

      - name: Detect changed skills
        id: changes
        run: |
          # Same space-join as the tessl job — keeps both the GHA output format
          # and the downstream `for skill in ${{ ... }}` loop working.
          CHANGED=$(git diff --name-only origin/main...HEAD -- skills/ | cut -d'/' -f2 | sort -u | tr '\n' ' ')
          CHANGED="${CHANGED%% }"
          echo "skills=$CHANGED" >> "$GITHUB_OUTPUT"

      - name: Validate changed skills
        if: steps.changes.outputs.skills != ''
        run: |
          for skill in ${{ steps.changes.outputs.skills }}; do
            echo "=== Validating: $skill ==="
            skills-ref validate "skills/$skill" || true
          done


================================================
FILE: .gitignore
================================================
__pycache__/
.DS_Store
evals/.results/
.pytest_cache/


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to Claude Bootstrap will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

---

## [5.8.0] - 2026-05-12

### Fixed

#### UX Fix Pass (12 issues from manual CLI testing)
- **Prompt character** — Changed from `maggy:` to `>` for cleaner input (`cli_chat.py:76`)
- **Ctrl+C during streaming** — Now cancels current response instead of exiting REPL. Added `except KeyboardInterrupt` in `_stream_chunks` (`cli_chat.py:161`)
- **`/health` 404** — Client was calling `/api/health/memory` (non-existent). Fixed to call `/api/engram/diagnostics` (`cli_client.py:260`)
- **`/route`, `/models`, `/budget`, `/stats`, `/health`, `/config` crash on server down** — Added `_call(fn, default)` safe wrapper that catches `Exception` and `SystemExit` from unreachable server. All display commands return fallback data instead of crashing (`cli_repl_cmds.py:18`)
- **Models shows "0 tracked" / "No data yet"** — When heatmap is empty, now shows the 5 known model tiers (local, kimi, gpt, claude, codex) with 0 samples (`cli_repl_cmds.py:129`)
- **`/use` accepts invalid model names** — Now validates against `_KNOWN_MODELS`, prints warning for unknown names while still setting the restriction (`cli_repl_cmds.py:147`)
- **Dir shows "?"** — Welcome banner now falls back to `os.getcwd()` when session `working_dir` is empty (`cli_welcome.py:36`)

### Added

#### Budget Subscription Awareness
- **`plan` field** on `BudgetConfig` — Users set `budget.plan: subscription` in `~/.maggy/config.yaml` (`config.py:150`)
- **`BudgetManager.budget_status()`** includes `plan` in response (`budget.py:163`)
- **`/budget`** shows "Subscription" instead of "$0.00 / $10.00" when plan is subscription (`cli_repl_cmds.py:87`)
- **Welcome banner** shows "Subscription" for subscription plans (`cli_welcome.py:54`)

#### Welcome Banner Improvements
- **Models count** — Shows "5 available" (known model count) instead of "0 tracked" when no heatmap data (`cli_welcome.py:62`)

### Changed
- **`_HELP` compressed** — 2-column layout saves 6 lines, fits all new features within 200-line limit (`cli_repl_cmds.py:191`)

### Tests
- `test_repl_cmds.py` — +5 tests: models_empty_shows_known, use_warns_unknown_model, budget_subscription_plan, health_graceful_failure, stats_server_down
- `test_cli_welcome.py` — +3 tests: dir_shows_cwd_fallback, models_shows_available_count, budget_subscription_welcome
- `test_cli_chat.py` — +1 test: chat_prompt_uses_angle_bracket
- **Total: 825 tests passing** (816 + 9 new)

---

## [5.7.0] - 2026-05-12

### Added

#### `/monitor` Command — Background Tracker Polling
- **`maggy/services/monitor.py`** — MonitorService with SQLite-backed polling for GitHub PRs and Monday.com items. `MonitorConfig` and `MonitorEvent` dataclasses, `add/remove/list_active/is_new/mark_seen/status/poll` methods
- **`maggy/providers/monday.py`** — Monday.com provider implementing `IssueTrackerProvider` protocol via GraphQL API. Maps board items to Task dataclass
- **`maggy/api/routes_monitor.py`** — REST endpoints: `GET /api/monitor/status`, `POST /api/monitor/start`, `POST /api/monitor/stop`
- **`/monitor` handler** in REPL — shows active monitor count (`cli_chat.py:94`)

#### `/health` Command — Memory Health Dashboard
- **`cmd_health()`** — Shows Engram health score (color-coded) and Mnemos fatigue state in Rich Panel (`cli_repl_cmds.py:180`)
- **`health_dashboard()`** and **`engram_diagnostics()`** client methods (`cli_client.py:259`)

#### Enhanced Welcome Banner
- **`cli_welcome.py`** — New file with Rich Panel welcome banner showing project info, budget, models, status, and memory health score

#### Search Routing to Local Model
- **"search" type** added to `TYPE_KEYWORDS` in `chat_router.py` — 11 keywords (find, search, grep, where, locate, which, look, scan, show, list, read) route to local/Qwen model for free

#### Account Switching Guidance
- **`maggy/services/account_guide.py`** — Detects CLI auth profiles from `~/.claude/`, `~/.codex/`. `suggest_switch()` returns CLI instructions, `render_switch_guide()` prints Rich-formatted guidance
- **Quota error detection** — `_QUOTA_MARKERS` in `cli_chat.py` triggers account switch guidance on rate limit errors

### Tests
- `test_monitor.py` — 8 tests for MonitorService
- `test_monday_provider.py` — 6 tests for MondayProvider
- `test_account_guide.py` — 5 tests for account switching
- `test_chat_router.py` — +3 tests for search type detection
- `test_repl_cmds.py` — +3 tests for health command
- `test_cli_welcome.py` — +2 tests for health and session history
- `test_cli_chat.py` — +1 test for quota error guidance
- **Total: 816 tests passing** (788 + 28 new)

---

## [5.1.0] - 2026-05-11

### Added

#### REPL Slash Commands — Stats, Routing, Model Control
- **`maggy/cli_repl_cmds.py`** — 9 command handlers for the interactive REPL:
  - `/stats` — Budget + model performance summary (spend, status, reward heatmap)
  - `/budget` — Detailed per-provider breakdown with visual progress bar
  - `/route` — Routing rules, task type overrides, model strengths/success rates
  - `/models` — Full reward heatmap grid by model × task type × blast tier
  - `/use claude,codex` — Restrict routing to specific models for this session
  - `/use all` — Remove model restriction
  - `/config` — Configuration summary (codebases, routing mode, budget limit)
  - `/claude-md` — Render project's CLAUDE.md in terminal
  - `/help` — List all available commands
- **`SessionState`** dataclass — Mutable session-level state (session_id, working_dir, allowed_models)
- **`dispatch()`** router — Parses slash commands, routes to handlers, returns True if handled
- **`GET /api/routing/rules`** endpoint — Exposes routing mode, task type overrides, model performance
- **`allowed_models`** field on `RoutedMessageRequest` — Server-side model restriction: if routed model not in allowed list, picks first allowed model with updated reason

#### Qwen3-Coder Benchmarks
- **75.7 tok/s average** — 3.4× faster than Qwen2.5-Coder (22.1 tok/s), 2× faster than Claude API (37.4 tok/s)
- MoE architecture (3.3B active / 30B total params) on M4 Max 128GB
- Quality: 10/10 BST correctness, 9/10 async rate limiter (token bucket + asyncio.Lock)
- Cold start: ~13s model load; hot runs: <100ms start

#### mWP Mindset — Full Framework
- **`skills/base/SKILL.md`** — Added complete mWP section with 11-Star Framework (Brian Chesky), mWP planning checklist (obvious → magical → multiplier)
- **`routing_rules.py`** — Expanded mWP convention injected into all CLI prompts (codex, kimi, qwen3, claude) with 3-question framework and 11-star reference

### Changed
- **`cli_chat.py`** — Integrated `SessionState` and `dispatch()` from `cli_repl_cmds`; passes `allowed_models` to `chat_send_routed()`; mode hint now shows `/help for commands`
- **`cli_client.py`** — Added `budget_by_provider()`, `routing_rules()` methods; updated `chat_send_routed()` signature to accept `allowed_models`
- **`benchmark-results.md`** — Qwen3-Coder results filled in (was TBD), quality assessment section added

### Tests
- `tests/test_repl_cmds.py` — 10 tests (dispatch routing, stats, budget, route, models, use, claude-md, help)
- `tests/test_cli_chat.py` — Updated 2 assertions for `allowed_models=None` parameter
- **Total: 653 tests passing** (643 maggy + 10 session detect)

---

## [5.0.0] - 2026-05-10

### Added

#### Interactive Chat — Session Takeover
- **`maggy/services/chat.py`** — ChatManager for interactive Claude sessions with SSE streaming
  - Auto-connects to all active CLI sessions (Claude, Codex, Kimi) via ActivityService process scanning
  - Session continuity with `--resume <session-id>` for multi-turn conversations
  - `CLAUDECODE` env var stripping to allow nested Claude subprocess spawning
  - `--verbose` flag for `--output-format stream-json` compatibility
  - Deduplication via dict keyed by project name
- **`maggy/services/chat_context.py`** — Context builder for session enrichment
  - Path-based history matching (not just exact project name) via `_path_candidates()`
  - `_SKIP_DIRS` set prevents matching common system directories (Users, Documents, Library)
  - Recent prompt injection from activity data per project
  - Claude `session_id` resolution from `~/.claude/history.jsonl` for true `--resume`
- **`maggy/api/routes_chat.py`** — Chat API (5 endpoints)
  - `POST /api/chat/auto-connect` — detect all active sessions, enrich with history context
  - `POST /api/chat/sessions` — create session
  - `GET /api/chat/sessions` — list sessions
  - `GET /api/chat/sessions/{id}` — get session + messages
  - `POST /api/chat/sessions/{id}/send` — send message, stream response via SSE
  - `DELETE /api/chat/sessions/{id}` — delete session
- **Chat UI** in `app.js` — full web-based chat interface
  - Auto-connects on tab load, shows all active project sessions in sidebar
  - Message thread with user/Claude bubbles
  - SSE EventSource for real-time streaming
  - Session history context display
  - New session creation from active + configured projects

#### Auto-Bootstrap — No Empty Tabs
- **`_bootstrap()` in `main.py`** — seeds all services on startup
  - `history.analyze()` — parses CLI sessions immediately (260+ sessions, 11,994 prompts)
  - `introspector.analyze()` — collects signals, emits events
  - `_seed_cikg()` — scans configured codebases, creates nodes for repos + detected languages

#### UI Navigation Cleanup
- **Grouped navigation** — 9 flat tabs reorganized into 3 logical groups:
  - **Work** (Chat, Tasks, Watching) — things you do
  - **Intel** (Competitors, Insights) — things you learn
  - **System** (gear dropdown: Budget, Models, Forge, Settings) — things you configure
- **Tab renames** — Inbox→Tasks, Followed→Watching, Process→Insights
- **Chat is default tab** — loads on startup, auto-connects immediately
- **Gear dropdown** — system tabs collapsed into icon menu, reduces nav clutter
- **Section labels** — tiny uppercase "WORK" / "INTEL" separators

#### Process Intelligence Tab Enhancement
- Parallel fetch of activity, history, improve, events, CIKG data
- Health signals display (routing, memory, reliability, cost percentages)
- Live activity section showing active sessions + recent prompts
- Session patterns from history analysis
- Button spinner feedback + success toast on Analyze History / Self-Improve

#### Infrastructure
- **No-cache static middleware** — `_NoCacheStatic` adds `Cache-Control: no-store` to `/static`
- **Cache-busting** — `?v=3` on script tag
- **`showToast()`** — green success notification for async operations

### Security
- **Chat path validation** — `project_path` now validated against configured codebase roots (blocks arbitrary filesystem access via `--dangerously-skip-permissions`)
- **Chat streaming lock** — per-session `asyncio.Lock` rejects concurrent `/send` requests, preventing duplicate subprocess spawning and workspace corruption

### Fixed
- Engram `expire_engrams` referencing `self` outside class context
- `auto_connect` returning duplicate sessions for same project
- `CLAUDECODE` env var blocking nested Claude subprocess spawning
- `--verbose` flag required when using `--output-format stream-json` with `-p`
- History matching missing projects stored under parent dir name (e.g. "AI-Playground" vs "claude-skills-package")
- Process tab buttons doing nothing due to browser-cached old JS
- 500-row limit in history store masking projects — switched to aggregated report data

### Changed
- Default tab: `inbox` → `chat`
- Org name in config: `"Your Org"` → read from `~/.maggy/config.yaml`
- README fully rewritten to reflect current feature set (was still describing MVP)

### Tests
- `tests/test_chat.py` — 17 tests (ChatManager + AutoConnect)
- `tests/test_chat_context.py` — 18 tests (path candidates, history matching, prompts, session ID)
- Total: **466 tests passing**

---

## [4.0.0] - 2026-05-05

### Added

#### Polyphony — Multi-Agent Orchestration (Core)
- **`scripts/polyphony/`** — Full multi-agent orchestration package with container-isolated workspaces. Each agent session runs in its own Docker container with independent git branches.
- **Domain models** (`models.py`) — Task, Identity, AgentProfile, RunSpec, Result dataclasses
- **Task state machine** (`state_machine.py`) — DISCOVERED -> CLAIMED -> ROUTED -> PROVISIONED -> RUNNING -> VERIFYING -> LANDED with FAILED/BLOCKED paths
- **SQLite store** (`store.py`) — Persistent CRUD for tasks, run_specs, results with state audit log
- **YAML config** (`config.py`) — Configuration loading from `~/.polyphony/` with defaults merging
- **5-dimension complexity scoring** (`scoring.py`) — Cyclomatic depth, fan-out, security boundary, concurrency, domain invariants (0-10 scale)
- **Pure function router** (`router.py`) — Task x Policy -> RunSpec, first-match rules with fallback chains
- **Identity broker** (`identity.py`) — Named credential bundles with volume mounts and env overlays
- **Workspace manager** (`workspace.py`) — Per-task git clone lifecycle with `--reference`/`--dissociate` mirror support
- **Docker runtime** (`runtime.py`) — Container create/start/stop/wait/logs/rm lifecycle
- **Event parser** (`events.py`) — NDJSON/stream-json parsing from container stdout
- **Orchestrator** (`orchestrator.py`) — Supervisor loop: discover -> claim -> route -> provision -> run -> verify -> land
- **Agent adapters** (`adapters/`) — Claude (`-p --output-format stream-json`), Codex (`exec --full-auto`), Kimi (`--print -y`)
- **Work sources** (`sources/`) — GitHub Issues via `gh api`, local SQLite task queue
- **CLI** (`__main__.py`) — `polyphony {init|spawn|status|cleanup}` commands
- **Skill** (`skills/polyphony/SKILL.md`) — Full documentation for the orchestration system
- **Commands** — `/polyphony-init`, `/polyphony-spawn`, `/polyphony-status`
- **Templates** — `Dockerfile.polyphony`, `polyphony-config.yaml`, `polyphony-identities.yaml`, `polyphony-agents.yaml`, `polyphony-routing.yaml`
- **Spec** (`docs/polyphony-spec.md`) — Full specification reference (12 sections)
- **173 tests** across 13 test files with full TDD coverage

---

## [3.6.1] - 2026-05-04

### Changed
- **Complexity-based delegation replaces file-count heuristic** (`skills/cross-agent-delegation/SKILL.md`) — Kimi delegation now scored on 5 dimensions (cyclomatic depth, fan-out, security boundary, concurrency, domain invariants) × 0-2 each, sourced from iCPG signals + Claude reasoning. Routing: 0-3 → Kimi solo, 4-6 → Kimi + Codex auto-review, 7-10 → Claude direct. Adds trivial-case shortcut (<2 files + no risk keywords → auto-Kimi without scoring) and single-dimension override (7+ in any one dim keeps Claude). PR #16.

---

## [3.6.0] - 2026-05-03

### Added

#### Cross-Tool Compatibility (Claude + Kimi + Codex)
- **`scripts/detect-agents.sh`** — Detects installed AI CLI tools (Claude Code, Kimi CLI, Codex CLI)
- **`scripts/install-skills.sh`** — Reusable skill copier for any target directory
- **`templates/AGENTS.md`** — Codex project instructions template (mirrors CLAUDE.md with `.agents/skills/` paths)
- **`templates/config.toml`** — Hooks in TOML format for Kimi/Codex compatibility
- **`scripts/convert-hooks-to-toml.sh`** — JSON to TOML hook converter (requires jq)
- **`commands/sync-agents.md`** — `/sync-agents` command for cross-tool config sync
- **`install.sh`** auto-detects and installs skills to `~/.kimi/skills/` and `~/.codex/skills/`
- **`/initialize-project`** question 9: "Which AI CLI tools do you use?" with auto-detection
- Cross-tool directories (`.kimi/`, `.codex/`, `.agents/`) added to `.gitignore` template

#### Cross-Agent Intelligence
- **`templates/codex-auto-review.sh`** — Stop hook that auto-runs Codex review on changed files
  - Checks for Critical/High severity issues only
  - Exit 0 = pass, Exit 2 = feed findings back to Claude for fixing
  - Truncates diff to 8000 chars to prevent Codex token overflow
  - Gracefully skips if Codex CLI not installed
- **`skills/cross-agent-delegation/SKILL.md`** — Delegation skill with:
  - Tool detection (checks `command -v` for each CLI)
  - iCPG blast radius rules for Kimi delegation (<=3 files suggest Kimi, 4-8 offer option, 9+ stay Claude)
  - iCPG mandatory pre-task queries for all agents (prior, constraints, risk)
  - Mnemos mandatory memory lifecycle for all agents (goals, checkpoints, fatigue)
  - 10-step cross-agent workflow summary
- **Codex auto-review Stop hook** added to `settings.json` (after TDD, before iCPG record, 120s timeout)
- **Codex auto-review TOML hook** added to `config.toml` for Kimi/Codex compatibility
- **Cross-Agent Workflow** section added to both `CLAUDE.md` and `AGENTS.md` templates
- **`cross-agent-delegation/`** added to always-copy skill list in `/initialize-project`

#### Tests
- **`tests/test_cross_tool.py`** — 12 tests for cross-tool compatibility (detect-agents, install-skills, templates, sync-agents)
- **`tests/test_cross_agent.py`** — 22 tests for cross-agent intelligence (codex-auto-review, delegation skill, settings.json hook ordering, config.toml, template refs)

### Changed
- `install.sh` bumped to v3.6.0
- `install.sh` now makes `codex-auto-review.sh` executable during install
- `tests/validate-structure.sh` includes cross-tool template validation
- Total skills increased from 60 to **61 skills**
- Total tests: 62 pytest + 238 validation checks

---

## [3.5.2] - 2026-04-22

### Fixed
- **Hook error behavior revised** — the 3.5.1 fix silently no-op'd missing scripts, which hid real installation problems. Hook commands now:
  - **Fail loud on real errors** — if the script exists and crashes, its stderr + non-zero exit propagate to Claude Code so you can debug
  - **Print one actionable line on missing installs** — `[claude-bootstrap] hook script 'X' not installed — run <claude-bootstrap>/install.sh …` and exit 0 (no blocking error, but you see exactly what to do)
  - **Use `exec` to run the resolved script** — exit code + stderr pass through unchanged
- **Hook scripts stop swallowing stderr** — removed 19 instances of `2>/dev/null` across `mnemos-*.sh`, `icpg-*.sh`, and `tdd-loop-check.sh`. Python tracebacks and Python stderr now surface to Claude Code's hook diagnostics. Command substitution (`$(...)`) only captures stdout, so this doesn't affect any value parsing.

## [3.5.1] - 2026-04-21

### Fixed
- **PreToolUse hook "Bash hook error" on any tool call.** `templates/settings.json` declared hook commands as relative paths (`scripts/mnemos-*.sh`) that don't exist in most projects — the scripts live in `templates/` and nothing copies them to `<project>/scripts/`. Every tool call triggered a hook-not-found error shown as `PreToolUse:Bash hook error` in the session (non-blocking but noisy).
- Hook commands now try `.claude/scripts/<name>.sh` first (project-local override), fall back to `$HOME/.claude/templates/<name>.sh` (always installed by `install.sh`), and no-op cleanly when neither exists. Applied to all 8 hook script references across `PreCompact`, `PreToolUse`, `PostToolUse`, `Stop`, and `SessionStart`.

---

## [3.5.0] - 2026-04-19

### CI
- **`skill-review.yml`**: both `tessl` and `skills-ref` jobs now space-join the detected-skills list before writing to `$GITHUB_OUTPUT`. The old plain `echo "skills=$CHANGED"` with a multi-line `$CHANGED` value failed GHA's output parser ("Invalid format") AND broke the downstream `for skill in ${{ outputs.skills }}` loop. Space-joining keeps both happy and unblocks multi-skill PRs (like this one, which touches both `maggy/` and `mnemos/`).

### Third review pass fixes (Copilot iteration)
- **Package renamed `src/` → `maggy/`.** The top-level `src` package name was a well-known Python packaging anti-pattern that collides with other projects. The Python code now lives at `claude-bootstrap/maggy/maggy/` and imports as `from maggy.X import Y` (matching the icpg/mnemos/skill_lint convention). `pyproject.toml` entrypoint + includes, `install.sh`, and the launcher commands updated to `python3 -m maggy.main`.
- **SQLite PRAGMAs** — `InboxService` and `CompetitorService` open connections via a shared helper that sets `journal_mode=WAL`, `foreign_keys=ON`, and `busy_timeout=30000`. Matches the convention used by `scripts/icpg/store.py` and prevents "database is locked" errors when the FastAPI handlers race the heartbeat worker.
- **Host-safety startup check** — `create_app()` now refuses to boot when `dashboard.auth_mode="local"` is combined with a non-loopback host (anything other than `127.0.0.1`/`localhost`/`::1`). Execute spawns `claude --dangerously-skip-permissions`, so binding to `0.0.0.0` with no auth would expose that to the local network. Users are directed to switch to token auth or rebind.
- **`is_configured()` no longer accepts `linear`** — `providers.build()` raises `NotImplementedError` for Linear (stub), so treating it as configured would crash `create_app()` at startup. Now returns `False` cleanly.
- **`providers.build()`** raises `NotImplementedError` with a clear "use github or asana" hint for `linear`.
- **GitHub provider logs non-200s** in `list_tasks` — previously a 401/403/404 silently yielded an empty inbox. Now WARNING-logged with the repo slug and first 200 chars of the response body for debuggability.
- **Removed unused `timedelta` import** from `inbox.py`.

### Second review pass fixes (CodeRabbit iteration 2)
- `AsyncAnthropic` used in async methods — inbox ranking + competitor discovery + daily briefing no longer block the event loop on multi-second LLM round-trips
- RSS/Google News feed date handling uses `parsedate_to_datetime` + ISO parser and compares real `datetime` objects — RFC 822 strings aren't lexicographically ordered (day-of-week cycles weekly)
- iCPG CLI invocation fixed: `python3 -m scripts.icpg query prior --text ...` against the real argparse entrypoint, not the utility submodule `scripts.icpg.symbols` which has no `__main__`
- Background `asyncio.create_task()` reference kept in a set + `add_done_callback(discard)` so GC can't kill the TDD pipeline mid-run
- `GitHubIssuesProvider.list_followed()` and `search_tasks()` refuse to run when `repos` is empty (otherwise the query has no repo filter and searches all of public GitHub)
- `AsanaProvider.list_tasks()` drops the dead `completed_filter` variable and skips sending `completed_since=""` (Asana validator rejects empty string); filters `closed` state properly
- `install.sh` enforces Python 3.11+ minimum (was only checking `python3` existed)
- `/static/index.html`: added CSP meta tag; Font Awesome pinned with SHA-384 SRI; Tailwind Play CDN annotated with vendor-for-prod TODO
- `static/app.js`: added `jsStr()` for JS-string-context escaping in inline onclick handlers (esc() alone leaves single quotes intact — XSS via ticket titles was possible)
- `regenerateBriefing()` catches and displays errors instead of swallowing them
- `commands/maggy.md`: reads `dashboard.host`/`dashboard.port` from config before probing health (was hardcoded 8080)
- `commands/maggy-init.md`: removed the "offer to write to .env" suggestion — the runtime doesn't load that file, so it would leave tokens on disk with no reader
- `config.example.yaml`: removed the Linear section (stub only, shouldn't be in the advertised selectable set)
- `PLAN.md`: config sample aligned with the actual runtime schema (removed spurious `config:` nesting)
- `maggy/README.md`: install path no longer assumes `~/Documents/AI-Playground/...`; uses relative `cd claude-bootstrap/maggy`
- `providers/__init__.py`: `__all__` alphabetized (RUF022)
- `skills/maggy/SKILL.md`: explicit permission-model disclosure box explaining the `--dangerously-skip-permissions` tradeoff and the `working_dir` whitelist mitigations

### Added
- **Maggy — AI engineering command center** (optional extension under `maggy/`)
  - Local FastAPI + vanilla JS dashboard; install with `maggy/install.sh`, zero build step
  - Provider abstraction: `GitHubIssuesProvider`, `AsanaProvider`, `LinearProvider` (stub) implement a single `IssueTrackerProvider` Protocol — swap trackers without touching services
  - AI-prioritized inbox with 30-min SQLite cache; stale-cache fallback when provider is unavailable
  - Generic competitor discovery + RSS + Google News monitoring with daily AI briefing (cached per day)
  - TDD execute pipeline (plan → tests → implement) spawns `claude -p --dangerously-skip-permissions` locally in the right codebase, with iCPG context auto-injected from the bootstrap's iCPG CLI
  - Config-driven (`~/.maggy/config.yaml`) — no hardcoded org IDs, repo names, or competitor lists
  - `/maggy` command launches dashboard; `/maggy-init` runs interactive setup
  - `skills/maggy/SKILL.md` documents capabilities; README skills table updated
- Maggy skill included in the skills table (fixes RI002 lint error for this PR)

### Fixed
- Added YAML frontmatter to `skills/mnemos/SKILL.md` (fixes FM001 lint error that was blocking CI on main)
- Skill lint now passes across all 60 skills

### Security (Maggy)
- RSS URL validation before fetching competitor feeds — blocks loopback, link-local, private-network, and non-HTTP(S) targets (SSRF prevention)
- `safeHref()` in dashboard JS — only allows `http(s)`/`mailto` schemes in external links, blocks `javascript:`/`data:` URIs that would slip past HTML escaping
- `working_dir` validated against configured codebase roots before launching Claude Code — prevents arbitrary-cwd execution of `--dangerously-skip-permissions`
- Execute-mode input validated via `Literal["tdd", "plan"]`; typos rejected at request boundary
- GitHub `_decode_id()` returns `None` on malformed input instead of raising — surfaces as 404 not 500
- LLM ranking output validated (index range, numeric rank, dedupe) before applying

### Resilience (Maggy)
- `provider.list_tasks` failure falls back to last cached ranking (flagged `stale=true`) instead of 500
- Route-level `_require_configured()` returns 503 + onboarding hint when `~/.maggy/config.yaml` is missing, instead of dereferencing `None` services
- `is_configured()` requires provider credentials (token) in addition to org/repos; refreshes cache on each check
- Claude subprocess kill on timeout (`proc.kill()` + `await proc.wait()`), non-zero exits marked as failed sessions
- `_run_claude()` returns `(ok, output)` tuple — TDD pipeline now aborts chain on first-step failure
- Competitor news events use deterministic SHA-256 IDs with `INSERT OR IGNORE` — prevents duplicate rows on cursor reset / overlapping scans

### Changed (Maggy)
- `pyproject.toml` console script `maggy = "src.main:main"` (proper callable) instead of `"src.main:app"` (ASGI instance)

---

## [3.4.1] - 2026-04-10

### Fixed
- Fixed broken `build-backend` in all three pyproject.toml files (icpg, mnemos, skill_lint). Changed `setuptools.backends._legacy:_Backend` to `setuptools.build_meta`. (Community reported)

### Added
- Cheeky personality section in CLAUDE.md template for new projects

---

## [3.4.0] - 2026-04-07

### Added
- **Skill Quality Gates** — Automated linter, CI integration, and behavioral evals
  - `scripts/skill_lint/` — Python package with 20 check rules across 4 categories:
    - Frontmatter (FM001-FM009): YAML validation, name/description/field checks
    - Spec (SP001-SP003, SR001): SKILL.md existence, line count limits, skills-ref integration
    - Content (CQ001-CQ006): ASCII art detection, vague phrase detection, filler intensity, code block density, stale references, H1 heading
    - References (RI001-RI002): Cross-skill link validation, README coverage
  - CLI: `PYTHONPATH=scripts python3 -m skill_lint [--format text|json] [--severity error|warning|info] [--skill NAME] [--fail-on error|warning] skills/`
  - Inline suppression: `<!-- skill-lint: disable=SP002 -->` in first 10 lines
  - 28 unit tests covering all check modules, report formatters, and CLI
  - `.github/workflows/skill-lint.yml` — Runs linter + tests on PR/push to skills/ or scripts/skill_lint/
  - `.github/workflows/skill-review.yml` — Tessl skill review + skills-ref validation on PRs (requires TESSL_TOKEN)
  - `evals/` — 18 behavioral eval scenarios for 15 skills with deterministic and LLM-judged criteria
  - `evals/run-evals.sh` — Eval runner with baseline comparison mode
- Updated `CONTRIBUTING.md` with quality gate requirements and linter usage

### Scan Results (59 skills)
- Errors: 1 (mnemos/ missing frontmatter)
- Warnings: 85 (19 skills over 500 lines, 30+ with ASCII art)
- Clean: 3 skills

---

## [3.3.2] - 2026-04-07

### Fixed
- Removed stale `Load with: base.md` line from all 53 skills. Since v3.0, base skill loads via `@include` in CLAUDE.md, not per-skill. The leftover line caused confusion about missing files. (Fixes #13)

### Housekeeping
- Closed #10 (Gen Agent Trust Hub security audit) — false positives from scanning markdown code samples as executable code.
- Closed #12 (Dispatch discoverability) — will address skill description metadata in a future cleanup pass.
- Closed #11 (Low quality skills) — will revisit with specific eval criteria.

---

## [3.3.1] - 2026-04-03

### Added
- **Post-Compaction Task Restoration** (Two-Layer Defense)
  - `templates/mnemos-post-compact-inject.sh` — PreToolUse hook (no matcher, fires on ALL tools) that detects compaction via `.mnemos/just-compacted` marker and re-injects the full checkpoint into Claude's context. Fast path ~5ms when no compaction, ~100ms injection when triggered.
  - `build_task_narrative()` in `checkpoint.py` — Reads signals.jsonl to build human-readable summary of recent activity (files edited, read counts, focus area, error patterns). Automatically included in checkpoints.
  - `format_for_post_compact_injection()` in `checkpoint.py` — Formats checkpoint as structured restoration block with goal, constraints, activity narrative, progress, key files, git state.
  - Compaction marker system (`write_compaction_marker`, `check_compaction_marker`, `consume_compaction_marker`) — Atomic marker write/consume to prevent parallel injection.

### Changed
- **`mnemos-pre-compact.sh`** — Enhanced from advisory to assertive. Now includes inline checkpoint content in preservation instructions, writes compaction marker for Layer 2, builds task narrative from signals, and uses stronger verbatim framing.
- **`CheckpointNode`** — Added `task_narrative` (str) and `recent_files` (list[dict]) fields for richer checkpoint content.
- **`settings.json`** — Added new PreToolUse entry (no matcher) for `mnemos-post-compact-inject.sh` before the existing Edit|Write matcher.
- **`SKILL.md`** — Documented post-compaction recovery mechanism.
- **`README.md`** — Rewrote Mnemos section with two-layer defense architecture, resilience failure mode table, "why not just a plain file" rationale, and post-compaction restoration flow diagram.

## [3.3.0] - 2026-04-03

### Added

#### Mnemos — Task-Scoped Memory Lifecycle
Agents crash when context fills up. Claude Code's compaction is lossy — it summarizes everything uniformly. Mnemos solves this with typed memory, continuous fatigue monitoring, and checkpoint/resume.

- **`scripts/mnemos/`** — Python package (zero external dependencies)
  - `models.py` — MnemoNode (8 types with typed eviction policies), FatigueState, CheckpointNode
  - `store.py` — SQLite MnemoGraph storage with mnemo_nodes, checkpoints, fatigue_log tables
  - `fatigue.py` — 4-dimension fatigue model from passively observed signals (no agent cooperation needed)
  - `signals.py` — Behavioral signal collection from hooks (scope scatter, re-read ratio, error density)
  - `checkpoint.py` — CheckpointNode write/load with iCPG bridge, git state capture, formatted resume output
  - `consolidation.py` — Micro-consolidation: compress ResultNodes, evict cold ContextNodes, decay weights
  - `__main__.py` — CLI: init, status, fatigue, checkpoint, resume, consolidate, nodes, add, bridge-icpg

- **4-Dimension Fatigue Model** (all passively observed from hooks):
  - Token utilization (0.40) — real context_window.used_percentage from statusline
  - Scope scatter (0.25) — unique directories in recent tool calls (from PreToolUse)
  - Re-read ratio (0.20) — files Read more than once, strongest signal of context loss (from PreToolUse)
  - Error density (0.15) — failed tool calls ratio (from PostToolUse)
  - States: FLOW (0-0.4), COMPRESS (0.4-0.6), PRE-SLEEP (0.6-0.75), REM (0.75-0.9), EMERGENCY (0.9+)

- **Auto-Feeding Token Signal**:
  - `templates/mnemos-statusline.sh` — Statusline receives `context_window` JSON from Claude Code, writes `fatigue.json`, delegates display to ccusage (if installed) or shows simple context %
  - JSONL fallback in PostToolUse — reads conversation JSONL to estimate context usage when statusline not configured (0.75 correction factor for cache overhead, ~1-2pp accuracy)
  - `statusLine` config added to `templates/settings.json` — auto-activates on install, no separate configuration needed

- **Fatigue-Aware Hook System**:
  - `templates/mnemos-pre-edit.sh` — PreToolUse: logs file signals, reads fatigue, auto-checkpoints at 0.60+, auto-consolidates at 0.40+, includes iCPG context
  - `templates/mnemos-post-tool.sh` — PostToolUse: logs tool success/failure for error density, auto-feeds token signal from JSONL when statusline is stale
  - `templates/mnemos-session-start.sh` — SessionStart: loads checkpoint on resume, bridges iCPG state
  - `templates/mnemos-pre-compact.sh` — PreCompact: emergency checkpoint + typed preservation priorities (NEVER DROP goals/constraints, OK TO DROP file contents)
  - `templates/mnemos-stop-checkpoint.sh` — Stop: writes final session checkpoint

- **MnemoNode Eviction Policies**:
  - GoalNodes, ConstraintNodes, CheckpointNodes, HandoffNodes: NEVER evicted
  - ResultNodes, WorkingNodes, SkillNodes: compressed first (summary kept), then evictable
  - ContextNodes: evictable when activation weight drops below threshold

- **iCPG Bridge**: `mnemos bridge-icpg` imports ReasonNodes as GoalNodes, postconditions/invariants as ConstraintNodes

- **Skill + Commands**:
  - `skills/mnemos/SKILL.md` — Full skill documentation with fatigue states, CLI reference, agent instructions
  - `commands/mnemos-status.md` — `/mnemos-status` slash command
  - `commands/mnemos-checkpoint.md` — `/mnemos-checkpoint` slash command

- **Documentation**:
  - `docs/mnemos-implementation.md` — Implementation addendum for the Mnemos RFC

### Changed

#### iCPG Fixes
- `scripts/icpg/bootstrap.py` — Fixed `_get_commits()` git log parsing (was producing 0 symbols linked)
- `scripts/icpg/drift.py` — Added `check_file_drift()` for fast, file-scoped drift (O(symbols-in-file))
- `scripts/icpg/__main__.py` — Added `drift file <path>` subcommand, `_resolve_path()` for relative path handling
- `templates/icpg-pre-edit.sh` — Now includes file-scoped drift detection alongside context and constraints

#### Settings Template
- `templates/settings.json` — Added `statusLine` config for auto-feeding token signal, Mnemos hooks replace standalone iCPG hooks, added PostToolUse hook, added mnemos permission allows
- `templates/CLAUDE.md` — Added `@.claude/skills/mnemos/SKILL.md` to skill includes

---

## [3.2.0] - 2026-04-02

### Added

#### iCPG Full Implementation (Intent-Augmented Code Property Graph)
- **`scripts/icpg/`** — Python CLI package implementing the full iCPG RFC v8
  - `models.py` — ReasonNode, Symbol, Edge, DriftEvent data models with Design by Contract (preconditions, postconditions, invariants)
  - `store.py` — SQLite storage layer with 4 tables, WAL mode, indexed queries
  - `symbols.py` — Language-aware symbol extraction: Python (AST), TypeScript/JS (regex), Go, Rust, Elixir
  - `drift.py` — 6-dimension drift detection: spec, decision, ownership, test, usage, dependency
  - `contracts.py` — Design by Contract layer with LLM inference (Claude/OpenAI) and heuristic fallback
  - `vectors.py` — Tiered duplicate detection: ChromaDB → TF-IDF → exact match fallback
  - `bootstrap.py` — Git history inference: cluster commits, LLM-infer ReasonNodes, link symbols
  - `__main__.py` — CLI with subcommands: init, create, record, query, drift, bootstrap, status
  - `pyproject.toml` — pip-installable with optional deps (chromadb, sentence-transformers, openai)

- **3 Canonical Pre-Task Queries** (RFC Section 2.1):
  - `icpg query prior "<goal>"` — Vector-based duplicate detection before starting work
  - `icpg query constraints <file>` — Get invariants/contracts for files being modified
  - `icpg query risk <symbol>` — Drift score, ownership history, modification count

- **Hook Integration**:
  - `templates/icpg-pre-edit.sh` — PreToolUse hook: injects intent context + constraints before every Edit/Write
  - `templates/icpg-stop-record.sh` — Stop hook: auto-records symbols to active ReasonNode after implementation

- **Slash Commands**:
  - `commands/icpg-impact.md` — `/icpg-impact <id>` blast radius visualization
  - `commands/icpg-why.md` — `/icpg-why <symbol>` trace symbol to creating intent
  - `commands/icpg-drift.md` — `/icpg-drift` full drift report across all dimensions
  - `commands/icpg-bootstrap.md` — `/icpg-bootstrap` infer intents from git history

### Changed

#### iCPG Skill Rewrite
- **`skills/icpg/SKILL.md`** — Complete rewrite aligning with RFC v8
  - ReasonNode now carries formal contracts (preconditions, postconditions, invariants)
  - Drift formally defined as predicate failure (not vague metric)
  - 6-dimension drift model with 0-1 severity scores per dimension
  - CLI reference for all `icpg` subcommands
  - Hook integration documentation (PreToolUse + Stop)
  - Agent Teams integration section with updated pipeline

#### Agent Team iCPG Integration
- **`skills/agent-teams/agents/team-lead.md`** — Team lead now creates ReasonNodes and checks for duplicates before creating task chains
- **`skills/agent-teams/agents/feature.md`** — Feature agents query constraints/risk before implementing, auto-record symbols after
- **`skills/agent-teams/agents/quality.md`** — Quality agent runs drift checks during GREEN verify, validates spec-intent alignment
- **`skills/agent-teams/SKILL.md`** — Updated "Integration with Existing Skills" table with iCPG + code-graph entries

#### Settings Template
- **`templates/settings.json`** — Added PreToolUse hook (icpg-pre-edit.sh), Stop hook extension (icpg-stop-record.sh), icpg permission allows

---

## [3.1.0] - 2026-04-02

### Added

#### iCPG Skill (Initial Spec)
- **`skills/icpg/SKILL.md`** — Initial iCPG skill spec (now superseded by 3.2.0 full implementation)

---

## [3.0.0] - 2026-03-31

### Breaking Changes

This release aligns Claude Bootstrap with how Claude Code actually works internally. Several features that referenced non-existent infrastructure have been replaced with real Claude Code mechanisms.

- **Ralph Wiggum plugin removed** — The `/ralph-loop` command, `claude-plugins-official` marketplace, and plugin stop-hook mechanism never existed in Claude Code. All references removed.
- **TDD loops now use real Stop hooks** — Claude Code's Stop hook (exit code 2 feeds stderr back to the model) replaces the fake plugin. `scripts/tdd-loop-check.sh` runs tests/lint/typecheck after each response.
- **`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` removed** — Agent spawning and task management are standard Claude Code features, not gated behind an env var. All references removed.
- **CLAUDE.md template uses `@include` directives** — Skills are loaded via `@.claude/skills/base/SKILL.md` syntax which Claude Code resolves at parse time (recursive, max depth 5, cycle detection).
- **Quality gates moved from CLAUDE.md to `.claude/rules/`** — Rules use YAML frontmatter with `paths:` globs for conditional activation.
- **"STRICTLY ENFORCED" / "Non-Negotiable" language removed** — Claude Code treats CLAUDE.md as user-level context (not system prompt) wrapped in `<system-reminder>` tags with "may or may not be relevant" caveat. Aggressive language wastes tokens without creating binding constraints.

### Added

#### Stop Hook TDD Loops
- **`templates/tdd-loop-check.sh`** — Universal TDD loop script for Stop hooks
  - Runs tests, lint, typecheck after each Claude response
  - Exit 0 (all pass) = Claude stops; Exit 2 (failures) = stderr fed back to Claude
  - Iteration counter with configurable max (default 25)
  - Detects project type (Node.js/Python) and runs appropriate commands
  - Distinguishes code errors (loop) from environment errors (stop)

- **`templates/settings.json`** — Pre-configured Claude Code settings
  - Stop hook configuration for TDD loops
  - SessionStart hook for auto-context injection
  - Permission allow rules: test runners, linters, git read commands, gh CLI
  - Permission deny rules: `rm -rf`, `git push --force`, writing `.env` files
  - Ready to copy into any project's `.claude/settings.json`

#### Conditional Rules System
- **`.claude/rules/` directory** with 7 rule files using proper YAML frontmatter:
  - `quality-gates.md` — Always active: 20 lines/function, 200 lines/file, 3 params, 80% coverage
  - `tdd-workflow.md` — Always active: RED-GREEN-VALIDATE workflow
  - `security.md` — Always active: no secrets in code, parameterized queries, bcrypt
  - `react.md` — Active on `**/*.tsx`, `**/*.jsx`, `src/components/**`
  - `typescript.md` — Active on `**/*.ts`, `**/*.tsx`
  - `python.md` — Active on `**/*.py`
  - `nodejs-backend.md` — Active on `src/api/**`, `src/routes/**`, `server/**`

#### CLAUDE.local.md
- **`templates/CLAUDE.local.md`** — Private developer override template
  - Not checked into git (higher priority than project CLAUDE.md)
  - Template with common overrides: preferences, local environment, quality gate tweaks

#### Agent Definition Frontmatter
- All 6 agent definitions now use proper Claude Code frontmatter:
  - `name` — Agent identifier
  - `description` — When-to-use hint
  - `model` — Model selection (sonnet, inherit)
  - `tools` — Tool allowlist (e.g., `[Read, Glob, Grep, TaskCreate]`)
  - `disallowedTools` — Tool denylist (e.g., `[Write, Edit, Bash]`)
  - `maxTurns` — Maximum agentic turns before stopping
  - `effort` — Thinking depth (medium/high)

#### @include Directives in CLAUDE.md
- CLAUDE.md template now uses `@.claude/skills/base/SKILL.md` syntax
- Claude Code resolves these at load time (recursively inlined)
- Skills actually become part of the prompt instead of decorative text

#### CLAUDE.md Template Structure
- Added **Project Structure** section — tells Claude where things live without filesystem exploration
- Added **Key Decisions** section — prevents Claude from re-litigating settled architectural choices
- Added **Conventions** section — patterns Claude should follow (test colocation, API shape, etc.)
- Added **Don't** section — short guardrails (no .env writes, no secret leaks)
- Removed Session Persistence section (belongs in skills, not root template)

#### PreCompact Hook for Smarter Compaction
- **`templates/pre-compact.sh`** — PreCompact hook that injects project-specific preservation priorities into the compaction summarizer
  - Auto-detects project type (TypeScript, Python, Next.js, FastAPI, Flutter, etc.)
  - Finds schema files (Drizzle, Prisma, SQLAlchemy) and tells summarizer to preserve all schema discussion verbatim
  - Finds API directories and tells summarizer to preserve exact endpoint paths, request/response shapes
  - Extracts Key Decisions from CLAUDE.md and tells summarizer to reference them by name
  - Injects live git state (branch, uncommitted changes, staged files) into summary priorities
  - Tells summarizer to preserve exact error messages and fix context (not paraphrased)
  - Tells summarizer what NOT to preserve (dead ends, full file contents, formatting noise)
  - Zero overhead during normal usage — only runs when compaction fires
  - Configured in `.claude/settings.json` under `hooks.PreCompact`

#### Full Skill Frontmatter (all 57 skills)
- Added undocumented-but-functional Claude Code skill frontmatter to all 57 skills:
  - `when-to-use` — guidance for when Claude should invoke the skill
  - `user-invocable` — 11 skills are user-invocable (code-review, codex-review, gemini-review, security, existing-repo, ticket-craft, workspace, cpg-analysis, playwright-testing, ai-models), 46 are model-only
  - `effort` — thinking depth per skill (6 high, 47 medium, 4 low)
  - `paths` — file glob patterns for 24 language/framework/database skills (e.g., `["**/*.py"]` for Python, `["**/*.tsx"]` for React)
  - `allowed-tools` — restricted tool access for 3 review/security skills (`[Read, Glob, Grep, Bash]`)

### Changed
- `install.sh` now copies rules/, templates/, and no longer checks for Ralph Wiggum plugin
- `iterative-development/SKILL.md` completely rewritten for Stop hooks
- `base/SKILL.md` — Ralph Wiggum auto-invoke section replaced with Stop hook explanation
- `agent-teams/SKILL.md` — Removed experimental env var requirement
- `commands/spawn-team.md` — Removed env var check, removed Shift+Up/Down and Ctrl+T UI references
- All agent definitions in `skills/agent-teams/agents/` rewritten with frontmatter
- Total files: 57 skills + 7 conditional rules + 3 templates

### Removed
- All Ralph Wiggum plugin references (`/ralph-loop`, `/plugin install`, `--completion-promise`, `<promise>` tags)
- `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` env var requirement
- Plugin marketplace references (`claude-plugins-official`)
- `Shift+Up/Down` and `Ctrl+T` UI interaction assumptions
- "STRICTLY ENFORCED" and "Non-Negotiable" language throughout

### Migration

```bash
cd "$(cat ~/.claude/.bootstrap-dir)"
git pull
./install.sh

# Then in each project:
claude
> /initialize-project
# Will update to v3.0.0 structure
```

**Manual steps for existing projects:**
1. Copy `templates/settings.json` to `.claude/settings.json`
2. Copy `templates/tdd-loop-check.sh` to `scripts/tdd-loop-check.sh` and `chmod +x`
3. Replace skill listings in CLAUDE.md with `@include` directives
4. Copy `rules/` files to `.claude/rules/`
5. Add `CLAUDE.local.md` to `.gitignore`
6. Remove `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` from environment

---

## [2.7.0] - 2026-03-23

### Added

#### Tiered Code Graph System (MCP-based)
- **Code Graph skill** (`code-graph/SKILL.md`) - Always-on code intelligence via MCP
  - "Graph first, file second" workflow — Claude queries the graph before reading files
  - Integrates with codebase-memory-mcp: 14 MCP tools, 64 languages, sub-ms queries
  - Decision tables for when to use graph vs direct file reads
  - Workflow: LOCATE → UNDERSTAND → BLAST → TRACE → CHANGE → VERIFY
  - Anti-patterns guide for common graph-ignoring mistakes

- **CPG Analysis skill** (`cpg-analysis/SKILL.md`) - Opt-in deep code analysis
  - Tier 2: Joern CPG via CodeBadger MCP (40+ tools, AST+CFG+CDG+DDG+PDG)
    - Control flow graph analysis, data flow tracing, dead code detection
    - CPGQL query examples for common analysis patterns
    - 12 language support (Java, Python, TypeScript, Go, C/C++, etc.)
  - Tier 3: CodeQL MCP for interprocedural taint analysis and security auditing
    - OWASP vulnerability detection, source-to-sink data flow
    - 10+ languages including Rust (which Joern doesn't support)
  - Combined workflow: Tier 1 scope → Tier 2 flow → Tier 3 security

- **Graph tools installer** (`scripts/install-graph-tools.sh`)
  - Platform-detecting installer (macOS/Linux, ARM64/AMD64)
  - `--joern` flag for Tier 2 (Docker + Python setup)
  - `--codeql` flag for Tier 3 (CodeQL CLI + query packs)
  - `--all` flag for all tiers

- **Post-commit graph hook** (`hooks/post-commit-graph`)
  - Lightweight (~10ms) hook that signals codebase-memory-mcp file watcher
  - Filters to code files only, never blocks git workflow
  - Auto-installed by `/initialize-project`

- **Graph freshness check** (`hooks/workspace/check-graph-freshness.sh`)
  - Session-start advisory warns if graph data is stale
  - Cross-platform timestamp comparison (macOS/Linux)

#### Initialize Project Updates
- New question 4b: "Code graph analysis level?" (Standard/Deep/Security/Full)
- New Step 4b: Automatic MCP server configuration (`.mcp.json`)
- `.code-graph/` auto-added to `.gitignore`
- Post-commit graph hook auto-installed
- CLAUDE.md template now includes "Code Graph (MCP)" section
- Summary output shows graph tier configuration

### Changed
- Total skills increased from 55 to **57 skills**
- `install.sh` now copies `install-graph-tools.sh` to `~/.claude/`
- `install.sh` summary output includes graph tools commands

---

## [2.6.0] - 2026-02-14

### Added

#### AI-Native Ticket Writing
- **Ticket Craft skill** - Write Jira/Asana/Linear tickets optimized for Claude Code execution
  - INVEST+C criteria: standard INVEST plus "Claude-Ready" verification
  - 4 ticket templates: Feature, Bug, Tech Debt, Epic Breakdown
  - Claude Code Context section: file refs, pattern refs, verification commands, constraints
  - Claude Code Ready Checklist: 16-point validation before tickets enter sprint
  - Anti-patterns guide: 6 common ticket-writing mistakes that cause AI agents to fail
  - Story point calibration for AI agents (different from human estimation)
  - Epic slicing techniques: by workflow, data variation, user role, CRUD, happy path
  - Given-When-Then acceptance criteria format
  - Integration guide for Jira, Asana, Linear, and GitHub Issues
  - Maps tickets directly to the agent-teams 10-task pipeline

#### Bug Fixes
- **Fix pre-push hook false positive** - Hook was blocking pushes even when review passed with 0 Critical/High issues (fixes #8, reported by @shawnyeager)
  - `grep` pattern matched "Critical" in table headers and pass messages
  - Now checks for explicit `Status: ✅ PASS` / `Status: ❌` lines instead

#### Community Contributions
- **Flexible install directory** - Bootstrap can now be cloned anywhere, not just `~/.claude-bootstrap` (PR #9 by @victortrac)
  - Install path saved to `~/.claude/.bootstrap-dir` for runtime resolution
  - Removes fragile symlink approach
- **Workspace skill frontmatter fix** - Added missing YAML frontmatter to workspace skill (PR #9 by @victortrac)

### Changed
- Total skills increased from 54 to **55 skills**

### Contributors
- @victortrac - Flexible install path, workspace skill fix (PR #9)
- @shawnyeager - Pre-push hook bug report (#8)

---

## [2.5.0] - 2026-02-07

### Added

#### Agent Teams (Default Workflow)
- **Agent Teams skill** - Coordinated team of AI agents as the default development workflow
  - Strict TDD pipeline: Specs > Tests > Fail > Implement > Test > Review > Security > Branch > PR
  - Task dependency chains enforce pipeline ordering (no step can be skipped)
  - Multiple features run in parallel with shared verification agents
  - Quality gates at every stage with cross-agent verification

- **Default agent roster** (5 permanent agents):
  - **Team Lead** - Orchestration only (delegate mode), task breakdown, feature agent spawning
  - **Quality Agent** - TDD verification (RED/GREEN phases), spec review, coverage >= 80%
  - **Security Agent** - OWASP scanning, secrets detection, dependency audit
  - **Code Review Agent** - Multi-engine code review (Claude/Codex/Gemini)
  - **Merger Agent** - Feature branches, PR creation via `gh` CLI

- **Feature agents** - One per feature, each follows the strict pipeline end-to-end
  - Writes spec, tests, implementation, validation
  - Hands off to Quality, Review, Security, Merger at each gate

- **Agent definition files** in `skills/agent-teams/agents/`:
  - `team-lead.md`, `quality.md`, `security.md`, `code-review.md`, `merger.md`, `feature.md`
  - Copied to `.claude/agents/` during project initialization

- **`/spawn-team` command** - Spawn the agent team on any project
  - Checks prerequisites (env var, agent definitions, feature specs)
  - Spawns all agents and creates task dependency chains
  - Shows team status summary

- **10-task dependency chain per feature**:
  1. Spec → 2. Spec Review → 3. Tests → 4. RED Verify → 5. Implement →
  6. GREEN Verify → 7. Validate → 8. Code Review → 9. Security Scan → 10. Branch+PR

### Changed
- Total skills increased from 53 to **54 skills**
- `/initialize-project` Phase 6 now sets up agent team by default (replaces manual next steps)
- CLAUDE.md template includes agent teams section
- `team-coordination.md` superseded by `agent-teams.md` for automated coordination

---

## [2.4.0] - 2026-01-20

### Added

#### Multi-Repo Workspace Awareness
- **Workspace skill** - Dynamic multi-repo and monorepo awareness for Claude Code
  - Workspace topology discovery (monorepo, multi-repo, hybrid detection)
  - Dependency graph generation (who calls whom)
  - API contract extraction (OpenAPI, GraphQL, tRPC, TypeScript, Pydantic)
  - Key file identification with token estimates
  - Cross-repo capability index (search before reimplementing)
  - Token budget management (P0-P3 priority allocation)

- **`/analyze-workspace` command** - Full workspace analysis
  - Phase 1: Topology discovery (~30s)
  - Phase 2: Module analysis (~60s)
  - Phase 3: Contract extraction (~45s)
  - Phase 4: Dependency graph (~30s)
  - Phase 5: Key file identification (~30s)
  - Generates TOPOLOGY.md, CONTRACTS.md, DEPENDENCY_GRAPH.md, KEY_FILES.md, CROSS_REPO_INDEX.md

- **`/sync-contracts` command** - Lightweight incremental contract sync
  - Checks only contract source files (~15s)
  - Diff mode to preview changes
  - Validate mode to check consistency
  - Lightweight mode for hooks

#### Contract Freshness System
- **Session start hook** - Staleness check (~5s, advisory)
- **Post-commit hook** - Auto-sync when contracts change (~15s)
- **Pre-push hook** - Validation gate (~10s, blocking)
- `.contract-sources` file to track monitored files
- Freshness indicators: 🟢 Fresh, 🟡 Stale, 🔴 Outdated, ⚠️ Drift

#### Cross-Repo Change Detection
- Automatic detection when changes affect other modules
- Impact analysis with recommended action order
- Breaking change protocol

### Changed
- Total skills increased from 52 to **53 skills**
- Added 3 new commands: `/analyze-workspace`, `/sync-contracts`, `/workspace-status`
- Added 3 workspace hooks for contract freshness

---

## [2.3.0] - 2026-01-17

### Added

#### Google Gemini Code Review
- **Gemini Review skill** - Google Gemini CLI for code review with Gemini 2.5 Pro
  - 1M token context window - analyze entire repositories at once
  - Free tier: 1,000 requests/day with Google account
  - Code Review Extension: `/code-review` command in Gemini CLI
  - Headless mode for CI/CD: `gemini -p "prompt"`
  - Benchmarks: 63.8% SWE-Bench, 56.3% Qodo PR, 70.4% LiveCodeBench

- **Multi-engine code review** - `/code-review` now supports up to 3 engines
  - Claude (built-in) - quick, context-aware reviews
  - OpenAI Codex - 88% security issue detection
  - Google Gemini - 1M token context for large codebases
  - Dual engine mode - run any two engines, compare findings
  - Triple engine mode - maximum coverage for critical/security code

- **GitHub Actions workflows** for all configurations
  - Gemini-only workflow
  - Triple engine (Claude + Codex + Gemini) workflow
  - Updated dual engine workflow

### Changed
- Total skills increased from 51 to **52 skills**
- Updated `/code-review` to support engine selection: `--engine claude,codex,gemini`
- Added `--gemini` and `--all` shortcuts for common configurations

---

## [2.2.0] - 2026-01-17

### Added

#### Existing Repository Support
- **Existing Repo skill** - Analyze existing codebases, maintain structure, setup guardrails
  - Repo structure detection (monorepo, full-stack, frontend-only, backend-only)
  - Tech stack auto-detection (TypeScript, Python, Flutter, Android, etc.)
  - Convention detection (naming, imports, exports, test patterns)
  - Guardrails audit (pre-commit hooks, linting, formatting, type checking)
  - Structure preservation rules - work within existing patterns, don't reorganize
  - Gradual implementation strategy for adding guardrails to legacy projects
  - Cross-repo coordination for separate frontend/backend repos

- **`/analyze-repo` command** - Quick analysis of any existing repository
  - Directory structure mapping
  - Guardrails status audit (Husky, pre-commit, ESLint, Ruff, commitlint, etc.)
  - Convention detection and documentation
  - Generates analysis report with recommendations
  - Offers to add missing guardrails
  - **Auto-triggered** by `/initialize-project` when existing codebase detected

#### Initialize Project Enhancement
- **Auto-analysis for existing codebases** - `/initialize-project` now automatically analyzes existing repos before making changes
- **User choice after analysis** - Options: skills only, skills + guardrails, full setup, or just view analysis
- **Existing-repo skill auto-copied** - When working with existing codebases

#### Guardrails Setup (for JS/TS and Python)
- **Husky + lint-staged** setup for JavaScript/TypeScript projects
- **pre-commit framework** setup for Python projects
- **commitlint** configuration for conventional commits
- **ESLint 9 flat config** template
- **Ruff + mypy** configuration for Python

### Changed
- Total skills increased from 50 to **51 skills**
- Updated README with `/analyze-repo` usage pattern

---

## [2.1.0] - 2026-01-17

### Added

#### Mobile Development (contributed by @tyr4n7)
- **Android Java skill** - MVVM architecture, ViewBinding, Espresso testing, GitHub Actions CI
- **Android Kotlin skill** - Coroutines, Jetpack Compose, Hilt DI, MockK/Turbine testing
- **Flutter skill** - Riverpod state management, Freezed models, go_router, mocktail testing
- **Android/Flutter auto-detection** - `/initialize-project` now detects Flutter, Android Java, and Android Kotlin projects

#### Database Skills (addresses #7)
- **Firebase skill** - Firestore, Auth, Storage, real-time listeners, security rules, offline persistence
- **Cloudflare D1 skill** - Serverless SQLite with Workers, Drizzle ORM integration, migrations
- **AWS DynamoDB skill** - Single-table design, GSI patterns, SDK v3 TypeScript/Python
- **AWS Aurora skill** - Serverless v2, RDS Proxy, Data API, connection pooling for Lambda
- **Azure Cosmos DB skill** - Partition key design, consistency levels, change feed, SDK patterns

#### Code Review Enhancements
- **Codex Review skill** - OpenAI Codex CLI for code review with GPT-5.2-Codex (88% detection rate)
- **Code review engine choice** - `/code-review` now lets you choose: Claude, OpenAI Codex, or both engines
- **Dual engine review mode** - Run both Claude and Codex, compare findings, catch more issues
- **CI/CD templates** - GitHub Actions workflows for Claude, Codex, and dual-engine reviews

### Changed
- Total skills increased from 44 to **50 skills**
- Updated README with new database and mobile skill listings

### Contributors
- @tyr4n7 - Android Java, Android Kotlin, Flutter skills and auto-detection
- @johnsfuller - Feature request for database skills (#7)

---

## [2.0.0] - 2026-01-08

### Breaking Changes
- **Skills structure changed** - Skills now use folder/SKILL.md structure instead of flat .md files
  - Before: `~/.claude/skills/base.md`
  - After: `~/.claude/skills/base/SKILL.md`
- All skills now require YAML frontmatter with `name` and `description` fields

### Added
- **Validation test** (`tests/validate-structure.sh`) - Validates skills structure, commands, hooks
  - `--full` mode: All 142 checks
  - `--quick` mode: Essential checks for initialize-project
- **Phase 0 validation** in `/initialize-project` - Checks bootstrap installation before setup
- **Conversion script** (`scripts/convert-skills-structure.sh`) - Migrates flat skills to folder structure
- Install script now runs validation automatically
- Symlink created at `~/.claude-bootstrap` for easy access to validation tools

### Fixed
- Skills now load properly in Claude Code (fixes #1)
- Install script properly copies skill folders instead of merging contents

### Migration
```bash
cd ~/.claude-bootstrap
git pull
./install.sh
```

---

## [1.5.0] - 2026-01-07

### Added
- **Code Deduplication skill** - Prevent semantic code duplication with capability index
- **Team Coordination skill** - Multi-person projects with shared state and todo claiming
- `/check-contributors` command - Detect solo vs team projects
- `/update-code-index` command - Regenerate CODE_INDEX.md
- Pre-push hook for code review enforcement

### Changed
- Code reviews now mandatory before push (blocks on Critical/High issues)

---

## [1.4.0] - 2026-01-06

### Added
- **Code Review skill** - Mandatory code reviews via `/code-review`
- **Commit Hygiene skill** - Atomic commits, PR size limits
- Pre-push hooks installation script

---

## [1.3.0] - 2026-01-05

### Added
- **MS Teams Apps skill** - Teams bots and AI agents with Claude/OpenAI
- **Reddit Ads skill** - Agentic ad optimization service
- **PWA Development skill** - Service workers, caching, offline support

---

## [1.2.0] - 2026-01-04

### Added
- **Playwright Testing skill** - E2E testing with Page Objects
- **PostHog Analytics skill** - Event tracking, feature flags
- **Shopify Apps skill** - Remix, Admin API, checkout extensions

---

## [1.1.0] - 2026-01-03

### Added
- Session management with automatic state tracking
- Decision logging for architectural choices
- Code landmarks for quick navigation

---

## [1.0.0] - 2026-01-01

### Added
- Initial release with 30+ skills
- `/initialize-project` command
- TDD-first workflow with Ralph Wiggum loops
- Security-first patterns
- Support for Python, TypeScript, React, React Native
- Supabase integration skills
- AI/LLM patterns for Claude and OpenAI


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Maggy

Thanks for your interest in contributing! This project aims to make AI-assisted development more reliable and consistent.

## Philosophy

Before contributing, understand the core philosophy:

1. **Complexity is the enemy** - Every line of code is a liability
2. **Measurable constraints** - Prefer specific numbers (20 lines/fn) over vague guidance
3. **Security is non-negotiable** - All projects must pass security checks
4. **AI-first thinking** - LLMs for logic, code for plumbing
5. **Spec-driven** - Define before you build

## How to Contribute

### Adding a New Skill

1. Create a directory in `skills/` with a lowercase hyphenated name
2. Add `SKILL.md` with YAML frontmatter:
   ```markdown
   ---
   name: my-skill
   description: One-line description of what this skill does
   when-to-use: When to activate this skill
   user-invocable: true
   effort: medium
   ---
   # My Skill

   ## Core Principles
   ...
   ```
3. Include these sections:
   - Core principles with measurable constraints
   - Project structure (if applicable)
   - Patterns with code examples (>= 1 per 50 lines)
   - Anti-patterns list
4. Keep under 500 lines (ideal: under 300)
5. Run the linter before submitting:
   ```bash
   PYTHONPATH=scripts python3 -m skill_lint --skill my-skill skills/
   ```
6. Update `README.md` to include the new skill

### Quality Gates

All skills must pass the automated linter before merge:

```bash
# Lint all skills
PYTHONPATH=scripts python3 -m skill_lint skills/

# Lint a single skill
PYTHONPATH=scripts python3 -m skill_lint --skill python skills/

# JSON output for CI
PYTHONPATH=scripts python3 -m skill_lint --format json skills/
```

**Checks enforced:**
- **FM001-FM009**: YAML frontmatter (name, description, format, fields)
- **SP001-SP003**: Spec compliance (SKILL.md exists, line count limits)
- **CQ001-CQ006**: Content quality (no ASCII art, no vague phrases, code examples)
- **RI001-RI002**: Cross-references (valid skill links, README listing)

Suppress known issues with inline comments:
```markdown
<!-- skill-lint: disable=SP002 -->
```

### Improving Existing Skills

1. Keep changes focused on one improvement
2. Maintain the existing structure
3. Ensure examples are correct and tested
4. Update version comments if significant

### Updating the Initialize Command

1. Test changes locally before submitting
2. Ensure idempotency - running twice shouldn't break anything
3. Preserve user customizations (never overwrite `_project_specs/`)

## Skill Guidelines

### Do

- Use specific, measurable constraints
- Provide working code examples
- Include anti-patterns with explanations
- Keep skills focused on one topic
- Reference other skills when building on them

### Don't

- Use vague guidance ("write clean code")
- Include time estimates
- Add features beyond what's needed
- Break existing projects when run as update

## Testing Your Changes

```bash
# Install your changes
./install.sh

# Test on a new project
mkdir test-project && cd test-project
claude
> /initialize-project

# Test on an existing project
cd existing-project
claude
> /initialize-project
# Should update skills without breaking existing config
```

## Pull Request Process

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/new-skill`)
3. Make your changes
4. Test locally
5. Submit PR with clear description of changes

## Code of Conduct

- Be respectful and constructive
- Focus on technical merit
- Welcome newcomers
- Share knowledge freely

## Questions?

Open an issue for:
- Bug reports
- Feature requests
- Clarification on philosophy
- Help with implementation


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2025 Ali Naqi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Maggy

> **From opinionated Claude Code setup to autonomous AI engineering platform.**

Maggy started as an opinionated project initialization system for Claude Code — skills, TDD hooks, quality gates. It has evolved into a full autonomous engineering command center: interactive chat with session takeover, multi-agent orchestration in containers, P2P mesh networking across machines, AI-prioritized task triage, competitor intelligence, and process analytics. The guardrails that keep AI-generated code simple, secure, and verifiable are still the foundation — but now they power an end-to-end autonomous engineering workflow.

**v5.0.0** — Interactive Chat (`--resume` session takeover), Polyphony (container-isolated multi-agent orchestration), P2P Mesh (cross-machine session sync), auto-bootstrap, grouped dashboard navigation.

## Core Philosophy

```
┌────────────────────────────────────────────────────────────────┐
│  TDD LOOPS VIA STOP HOOKS                                      │
│  ─────────────────────────────────────────────────────────────│
│  Stop hooks run tests after each Claude response.              │
│  Failures feed back automatically. Claude iterates until green.│
│  Real Claude Code infrastructure — no plugins needed.          │
├────────────────────────────────────────────────────────────────┤
│  TESTS FIRST, ALWAYS                                           │
│  ─────────────────────────────────────────────────────────────│
│  Features: Write tests → Watch them fail → Implement → Pass    │
│  Bugs: Find test gap → Write failing test → Fix → Pass         │
│  No code ships without a test that failed first.               │
├────────────────────────────────────────────────────────────────┤
│  SIMPLICITY IS THE GOAL                                        │
│  ─────────────────────────────────────────────────────────────│
│  20 lines per function │ 200 lines per file │ 3 params max     │
│  Enforced via .claude/rules/ with paths: frontmatter.          │
├────────────────────────────────────────────────────────────────┤
│  SECURITY BY DEFAULT                                           │
│  ─────────────────────────────────────────────────────────────│
│  No secrets in code │ Permission deny rules for .env files     │
│  Dependency scanning │ Pre-commit hooks │ CI enforcement       │
├────────────────────────────────────────────────────────────────┤
│  AGENT TEAMS BY DEFAULT                                        │
│  ─────────────────────────────────────────────────────────────│
│  Every project runs as a coordinated team of AI agents.        │
│  Agent definitions use proper frontmatter: tools, model,       │
│  maxTurns, effort, disallowedTools.                            │
├────────────────────────────────────────────────────────────────┤
│  CONDITIONAL RULES                                             │
│  ─────────────────────────────────────────────────────────────│
│  Rules in .claude/rules/ activate based on file paths.         │
│  React rules only load when editing .tsx files.                │
│  Python rules only load when editing .py files.                │
│  Saves tokens. Reduces noise. More targeted guidance.          │
└────────────────────────────────────────────────────────────────┘
```

## Quick Start

```bash
# Clone and install (clone anywhere you like)
git clone https://github.com/alinaqi/claude-bootstrap.git
cd claude-bootstrap && ./install.sh

# In any project directory
claude
> /initialize-project
```

Claude will:
1. **Validate tools** - Check gh, vercel, supabase CLIs
2. **Ask questions** - Language, framework, AI-first?, database, graph analysis level
3. **Set up repository** - Create or connect GitHub repo
4. **Create structure** - Skills, rules, settings, security, CI/CD, specs, todos
5. **Copy settings.json** - Pre-configured permissions and Stop hooks
6. **Generate CLAUDE.md** - With `@include` directives for modular skills
7. **Generate CLAUDE.local.md** - Template for private developer overrides
8. **Spawn agent team** - Deploy Team Lead + Quality + Security + Review + Merger + Feature agents

## Cross-Tool Compatibility (Claude + Kimi + Codex)

Maggy works with **Claude Code**, **Kimi CLI**, and **OpenAI Codex CLI**. All three use the same `SKILL.md` format.

| Feature | Claude Code | Kimi CLI | Codex CLI |
|---------|-------------|----------|-----------|
| Skills | `.claude/skills/` | `.kimi/skills/` (also reads `.claude/`) | `.codex/skills/` |
| Project instructions | `CLAUDE.md` | (uses skills) | `AGENTS.md` |
| Hooks config | `settings.json` | `config.toml` | `config.toml` |

**`install.sh`** auto-detects installed tools and installs skills to all of them.

**`/sync-agents`** syncs project config across tools on demand.

```bash
# Install tools
curl -L code.kimi.com/install.sh | bash     # Kimi
npm i -g @openai/codex                       # Codex

# Reinstall to pick up new tools
cd maggy && ./install.sh

# In any project, sync cross-tool config
claude
> /sync-agents
```

## Cross-Agent Intelligence

When multiple AI CLI tools are installed, Maggy enables intelligent collaboration between them.

### Codex Auto-Review (Stop Hook)

After tests pass, Codex automatically reviews your diff for critical bugs and security issues. Runs as a Stop hook between TDD and iCPG recording.

```
Stop hook order:
1. tdd-loop-check.sh     → tests pass?
2. codex-auto-review.sh  → Codex reviews diff (NEW)
3. icpg-stop-record.sh   → record symbols
4. mnemos-checkpoint.sh   → save memory
```

- Exit 0 = no critical issues found
- Exit 2 = critical/high issues feed back to Claude for fixing
- Gracefully skips if Codex not installed

### Kimi Delegation (Token Optimization)

Claude checks iCPG blast radius and delegates small tasks to Kimi automatically — the user doesn't run anything:

| Blast Radius | Claude's Action |
|-------------|----------------|
| 1-3 files | Saves context via `mnemos checkpoint`, runs `kimi --print -y -p "..."` with context + task |
| 4-8 files | Asks user, then delegates or handles directly |
| 9+ files | Handles directly (needs full context window) |

Context transfer uses structured state (mnemos checkpoints + iCPG constraints), not raw conversation.

### iCPG + Mnemos (Always-On for All Agents)

All three tools run the same iCPG pre-task queries and Mnemos memory lifecycle:

```bash
# Before any code change (Claude, Kimi, or Codex):
icpg query prior "<goal>"        # check for duplicate work
icpg query constraints <file>    # check invariants
icpg query risk <symbol>         # check fragility

# Memory management:
mnemos add goal "<task>"         # at task start
mnemos checkpoint                # at sub-goal boundaries
```

## How TDD Loops Work (Stop Hooks)

**No plugins. No fake commands.** Claude Code's Stop hook runs a script when Claude finishes a response. Exit code 2 feeds stderr back to Claude and continues the conversation.

```
┌─────────────────────────────────────────────────────────────┐
│  1. You say: "Add email validation to signup"               │
│  2. Claude writes tests + implementation                    │
│  3. Claude finishes response                                │
│  4. Stop hook runs: npm test && npm run lint                │
│  5a. All pass (exit 0) → Done!                              │
│  5b. Failures (exit 2) → stderr fed back to Claude          │
│  6. Claude sees failures, fixes, finishes again             │
│  7. Stop hook runs again → repeat until green               │
└─────────────────────────────────────────────────────────────┘
```

**Configuration** in `.claude/settings.json`:

```json
{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "scripts/tdd-loop-check.sh",
        "timeout": 60,
        "statusMessage": "Running tests..."
      }]
    }]
  }
}
```

The `tdd-loop-check.sh` script runs tests, lint, and typecheck. It tracks iteration count (max 25) and distinguishes code errors (loop) from environment errors (stop).

## @include Directives

CLAUDE.md uses `@include` to modularly load skills:

```markdown
# CLAUDE.md
@.claude/skills/base/SKILL.md
@.claude/skills/iterative-development/SKILL.md
@.claude/skills/security/SKILL.md
```

These are **resolved at load time** by Claude Code — the content is recursively inlined (max depth 5, cycle detection built in). This means skills actually become part of the prompt instead of just being listed as text.

## Conditional Rules

Rules in `.claude/rules/` use YAML frontmatter with `paths:` to activate only when relevant files are being edited:

```yaml
# .claude/rules/react.md
---
paths: ["src/components/**", "**/*.tsx"]
---
Prefer functional components with hooks...
```

```yaml
# .claude/rules/python.md
---
paths: ["**/*.py"]
---
Use type hints, pytest, ruff...
```

**Included rules:**

| Rule | Activates When |
|------|----------------|
| `quality-gates.md` | Always (no paths: filter) |
| `tdd-workflow.md` | Always |
| `security.md` | Always |
| `react.md` | Editing .tsx/.jsx files |
| `typescript.md` | Editing .ts/.tsx files |
| `python.md` | Editing .py files |
| `nodejs-backend.md` | Editing api/routes/server files |

## Smarter Compaction (PreCompact Hook)

Claude Code's built-in compaction fires at ~83% context and summarizes everything into 20K tokens using a generic 9-section template. It doesn't know what YOUR project cares about.

The PreCompact hook fixes this by injecting **project-specific preservation priorities** into the summarizer:

```
┌─────────────────────────────────────────────────────────────┐
│  Built-in compaction:                                       │
│  "Summarize this conversation" → generic summary            │
├─────────────────────────────────────────────────────────────┤
│  With PreCompact hook:                                      │
│  "Summarize, but preserve ALL schema decisions verbatim,    │
│   keep exact error messages, keep API contract details,     │
│   reference these Key Decisions by name, and here's the     │
│   current git state to include" → project-aware summary     │
└─────────────────────────────────────────────────────────────┘
```

The hook auto-detects:
- **Project type** (TypeScript/Next.js, Python/FastAPI, Flutter, etc.)
- **Schema files** (Drizzle, Prisma, SQLAlchemy) → tells summarizer to preserve schema discussion
- **API directories** → tells summarizer to preserve endpoint paths and contracts
- **Key Decisions from CLAUDE.md** → tells summarizer to reference them by name
- **Git state** → injects branch, uncommitted changes, staged files

Zero overhead during normal usage. Only runs when compaction actually fires.

## Mnemos — Task-Scoped Memory Lifecycle

Claude Code's built-in compaction is lossy and unreliable. It sometimes doesn't fire, `/compact` and `/clear` can fail (especially in multi-agent executions), and crashes/restarts lose all context. Mnemos provides **disk-persistent structured state** that survives all of these failure modes.

```
┌─────────────────────────────────────────────────────────────┐
│  DEFAULT CLAUDE CODE          vs  WITH MNEMOS               │
├─────────────────────────────────────────────────────────────┤
│  Blind until 83.5%               Continuous 4-dim monitoring│
│  Sudden hard compaction           Graduated: 40→60→75→83%   │
│  Uniform summarization            Typed: goals never evict  │
│  No cross-session memory          Auto checkpoint/resume    │
│  Crash = total context loss       Crash = resume from disk  │
│  Multi-agent: no shared state     Per-agent structured state│
│  No behavioral awareness          Detects re-reads, scatter │
└─────────────────────────────────────────────────────────────┘
```

### Post-Compaction Task Restoration (Two-Layer Defense)

When compaction fires, the built-in summarizer often drops task-specific state. Mnemos uses two independent layers to guarantee restoration:

```
BEFORE COMPACTION                    AFTER COMPACTION

PreCompact hook fires                First tool call → PreToolUse fires
├── Write emergency checkpoint       ├── Detect ".mnemos/just-compacted" marker
├── Build task narrative from        ├── Read checkpoint-latest.json
│   signals.jsonl (files, tools)     ├── Output full checkpoint into context
├── Output STRONG preservation       ├── Delete marker (one-shot)
│   instructions to summarizer       └── Claude now has: summary + checkpoint
└── Write ".mnemos/just-compacted"
    marker file                      = Task fully restored
```

**Layer 1** (best-effort): PreCompact tells the summarizer what to keep, including inline checkpoint content with typed eviction priorities.

**Layer 2** (guaranteed): Post-compaction injection via PreToolUse re-injects the full checkpoint on the first tool call after compaction. Doesn't depend on the summarizer. Fast path ~5ms when no compaction occurred.

### Why Not Just Write to a Plain File?

You could — but you'd immediately face: what format? When to update? How to distinguish "this is critical" from "this is nice to have"? The MnemoGraph's typed nodes solve this:

| Node Type | Eviction Policy | Example |
|-----------|----------------|---------|
| GoalNode | NEVER evict | "Implement auth module" |
| ConstraintNode | NEVER evict | "API backward compatibility" |
| ResultNode | Compress first | "JWT middleware tested" → summary kept |
| WorkingNode | Compress first | Current reasoning / in-progress analysis |
| ContextNode | Evictable | File contents → re-read from disk |

Without typed priorities, a checkpoint is just a blob. With them, the system knows goals > constraints > working memory > context, and makes intelligent decisions about what to restore within token budgets.

### Resilience Beyond Normal Compaction

The real value isn't the happy path — it's when things go wrong:

| Failure Mode | CC Built-in | Mnemos |
|---|---|---|
| Session crash/collapse | Context gone | Checkpoint on disk survives |
| `/compact` doesn't fire | Truncation at limit | Fatigue hooks wrote checkpoints earlier |
| Multi-agent child dies | No recovery | Child's `.mnemos/` has structured state |
| Forced restart | Generic summary | SessionStart reloads full checkpoint |
| `/clear` fails in multi-agent | Stuck in weird state | MnemoGraph is independent of CC's state |

### Fatigue Model

4 dimensions passively observed from hooks — no agent cooperation needed:

| Dimension | Weight | Signal Source | Detects |
|-----------|--------|---------------|---------|
| Token utilization | 0.40 | Statusline JSON | How full the context window is |
| Scope scatter | 0.25 | PreToolUse file paths | Agent bouncing between directories |
| Re-read ratio | 0.20 | PreToolUse Read calls | Agent re-reading files (context loss) |
| Error density | 0.15 | PostToolUse outcomes | Agent struggling (high error rate) |

Fatigue states: **FLOW** (0-0.4) → **COMPRESS** (0.4-0.6) → **PRE-SLEEP** (0.6-0.75) → **REM** (0.75-0.9) → **EMERGENCY** (0.9+). The fatigue model ensures checkpoints are written *before* things go wrong — so when a crash happens at 0.85, you have a recent checkpoint from 0.6.

### CLI

```bash
mnemos init                    # Initialize .mnemos/
mnemos status                  # Node counts + fatigue
mnemos fatigue                 # Detailed 4-dimension breakdown
mnemos checkpoint --force      # Write checkpoint now
mnemos resume                  # Output checkpoint for session inject
mnemos add goal "Build auth"   # Create a GoalNode
mnemos bridge-icpg             # Import iCPG ReasonNodes
```

**Overhead:** ~5ms per tool call (fast path), 84KB on disk. Token signal auto-feeds via statusline.

## iCPG — Intent-Augmented Code Property Graph

iCPG tracks *why* code exists, not just what it does. Every code change is linked to a ReasonNode that captures the intent, postconditions, and invariants.

```bash
icpg create "Implement auth" --scope src/auth/   # Create intent
icpg record src/auth/middleware.ts                # Link symbols
icpg query constraints src/auth/middleware.ts     # Get invariants
icpg drift                                        # Check for drift
icpg bootstrap                                    # Infer from git history
```

**Pre-Task Queries** (injected automatically via PreToolUse hook):
- `icpg query context <file>` — What intents touch this file?
- `icpg query constraints <file>` — What invariants must hold?
- `icpg drift file <file>` — Has this file drifted from its intent?

**6-Dimension Drift Detection:** spec drift, decision drift, ownership drift, test drift, usage drift, dependency drift.

## Maggy Dashboard — AI Engineering Command Center (Optional)

Maggy is a full-featured AI engineering command center. Install once, point it at your codebases and issue tracker, and get an interactive dashboard with chat, task triage, competitor intelligence, process analytics, and P2P session sync.

```bash
cd maggy/maggy
./install.sh

# Edit ~/.maggy/config.yaml — set your org, GitHub repos, codebase paths
export GITHUB_TOKEN=ghp_...
export ANTHROPIC_API_KEY=sk-ant-...

python3 -m maggy.main   # Open http://localhost:8080
```

Or from inside any Claude Code session:

```
/maggy-init   # Interactive setup wizard
/maggy        # Launch dashboard
```

### What it does

- **Interactive Chat** — auto-connects to all active Claude/Codex/Kimi sessions, SSE streaming, session continuity via `--resume`, path-based history matching
- **AI-prioritized Tasks** — Claude ranks your open issues by urgency, OKR alignment, and recency. 30-min SQLite cache with stale-cache fallback.
- **One-click Execute** — spawns `claude -p` locally in the right codebase, with iCPG context pre-injected. Runs a TDD pipeline, then commits locally for your review.
- **Competitor Intelligence** — AI-discovered competitors in whatever domain you configure, plus daily news briefing from RSS + Google News.
- **Process Insights** — CLI session history analysis, health signals, self-improvement recommendations, event spine queries.
- **P2P Mesh** — WebSocket-based multi-node session sync and handoff across machines, org-scoped networks, state quarantine.
- **Auto-Bootstrap** — all services seed themselves on startup (history, CIKG, events). No empty tabs.
- **Provider-agnostic** — GitHub Issues, Asana, or (stubbed) Linear. Swap trackers without touching services.

### Dashboard Navigation

Navigation is grouped by intent — 3 groups instead of 9 flat tabs:

| Group | Tabs | Purpose |
|-------|------|---------|
| **Work** | Chat, Tasks, Watching | Do things — chat with Claude, triage issues |
| **Intel** | Competitors, Insights | Learn things — competitor news, session analytics |
| **System** | Budget, Models, Forge, Settings | Configure — spend limits, model routing, MCP gaps |

Chat is the default tab — auto-connects to all running CLI sessions on load.

### Architecture

```
maggy/
├── maggy/                           # optional dashboard — run ./install.sh to enable
│   ├── maggy/                       # Python package (importable as `maggy`)
│   │   ├── main.py                  # FastAPI entry + auto-bootstrap
│   │   ├── config.py                # ~/.maggy/config.yaml loader
│   │   ├── providers/               # GitHub, Asana, Linear (stub)
│   │   ├── services/                # chat, inbox, competitor, executor, activity
│   │   ├── api/                     # REST endpoints (chat, mesh, process, etc.)
│   │   ├── mesh/                    # P2P networking (discovery, sync, WebSocket)
│   │   ├── process/                 # Process intelligence (patterns, signals, router)
│   │   ├── history/                 # CLI session history parsers (Claude, Codex, Kimi)
│   │   ├── improve/                 # Self-improvement (signals, analyzer)
│   │   ├── cikg/                    # Code Intelligence Knowledge Graph
│   │   ├── engram/                  # Memory entries (write/query/expire)
│   │   ├── event_spine/             # Structured event emission + querying
│   │   ├── forge/                   # MCP capability gap detection
│   │   ├── heartbeat/               # Scheduled jobs (history, engram, mesh sync)
│   │   └── static/                  # Dashboard (Tailwind + vanilla JS, no build step)
│   ├── tests/                       # 468 tests
│   └── install.sh                   # one-line install
├── commands/maggy.md                # /maggy command
├── commands/maggy-init.md           # /maggy-init wizard
└── skills/maggy/SKILL.md            # skill reference
```

### Config-driven, no hardcoded anything

One `~/.maggy/config.yaml` drives everything — org name, domain, repos, codebase paths, competitor categories. No hardcoded board IDs or team lists.

```yaml
org: { name: "Acme Corp", domain: "fintech" }
issue_tracker:
  provider: "github"           # or "asana"
  github:
    org: "acmecorp"
    repos: ["acmecorp/api", "acmecorp/web"]
codebases:
  - { path: "~/dev/acmecorp/api", key: "api" }
  - { path: "~/dev/acmecorp/web", key: "web" }
competitors:
  categories: ["fintech", "embedded-finance"]
```

### Safety model

Execute and Chat both run Claude Code with `--dangerously-skip-permissions` so subprocesses aren't blocked waiting on approval prompts with no terminal attached. Mitigations in place:

- `working_dir` and `project_path` are **validated against configured codebase roots** — both Execute and Chat reject arbitrary filesystem paths
- **Per-session streaming lock** — `asyncio.Lock` prevents concurrent subprocess spawning via the Chat API
- Dashboard **refuses to boot** if `auth_mode="local"` is combined with a non-loopback host (would expose Execute on the local network)
- RSS URLs **SSRF-validated** before fetching (blocks loopback, private, link-local)
- `CLAUDECODE` env var stripped from subprocesses to allow nested Claude sessions
- **No-cache static middleware** — `Cache-Control: no-store` prevents stale JS

See `maggy/README.md` for the full hardening notes.

### P2P Mesh Network

Multi-node session sync and handoff across machines. Each Maggy instance is a mesh peer that can share memory, discover other nodes, and synchronize state.

| Component | What it does |
|-----------|-------------|
| **Peer Discovery** | Registry of known peers with address, org, last-seen tracking |
| **Git Discovery** | Auto-discovers peers from shared git remotes across configured codebases |
| **WebSocket Server/Client** | Bidirectional real-time communication between peers |
| **Mesh Protocol** | 7 message types: `hello`, `share`, `request`, `response`, `quarantine`, `promote`, `heartbeat` |
| **Quarantine** | Untrusted data from peers is quarantined until reviewed — prevents poisoned memory injection |
| **Org Scoping** | Peers are filtered by org key so only your team's nodes connect |
| **Provenance** | Tracks origin of shared data (which peer, when, confidence level) |

Configure in `~/.maggy/config.yaml`:

```yaml
mesh:
  enabled: true
  port: 8080
  orgs: ["my-team"]
  git_discovery: true
  share_interval: 600
```

### Engram Memory

Persistent memory system with typed records, namespace isolation, and multi-path retrieval. Engrams survive across sessions — they're stored in SQLite, not in-context.

| Field | Purpose |
|-------|---------|
| `memory_type` | `fact`, `decision`, `code_ref`, `handoff` |
| `origin` | `explicit` (user-created), `inferred` (AI-derived), `mesh` (from peer) |
| `validity` | `active`, `superseded`, `expired` |
| `confidence` | 0.0-1.0 trust score |
| `namespace` | Project/session scoping |
| `expires_at` | Optional TTL for auto-expiry |

Retrieval paths: by namespace, by type, by keyword, by tag, or most recent. The heartbeat scheduler runs periodic expiry to clean stale entries.

### Event Spine

Structured event emission and querying across all Maggy services. Every significant action (task executed, competitor discovered, history analyzed, self-improvement run) emits a typed event with a standard header.

Events are stored in SQLite and queryable via the `/api/events` endpoint. The Insights tab visualizes event streams for debugging and auditing service behavior.

### Other Subsystems

| Subsystem | Purpose |
|-----------|---------|
| **CIKG** | Code Intelligence Knowledge Graph — codebase nodes, technology detection, landscape queries |
| **Forge** | MCP capability gap detection — scans filesystem patterns, suggests MCP tools to fill gaps |
| **History** | CLI session history parsers for Claude, Codex, and Kimi — topic extraction, session patterns |
| **Improve** | Self-improvement — signal collection, health scoring, actionable recommendations |
| **Budget** | Daily token spend limits with per-provider breakdown |
| **Model Router** | Reward-based heatmap for model selection by task type |
| **Heartbeat** | Scheduled jobs — history refresh, engram expiry, self-improvement, mesh sync |

## Pre-configured Permissions

`.claude/settings.json` includes permission rules so users don't get pestered for routine operations:

```json
{
  "permissions": {
    "allow": [
      "Bash(npm test *)",
      "Bash(npm run lint *)",
      "Bash(pytest *)",
      "Bash(git status *)",
      "Bash(gh pr *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force *)",
      "Write(.env)",
      "Write(.env.*)"
    ]
  }
}
```

## CLAUDE.local.md (Private Overrides)

Each developer gets a `.gitignore`'d `CLAUDE.local.md` for personal preferences:

```markdown
# My Preferences
- I prefer verbose explanations
- My local DB runs on port 5433
- Use pnpm instead of npm
```

This loads at **higher priority** than project `CLAUDE.md` — personal preferences override team config without polluting the repo.

## Agent Teams

Every project runs as a coordinated team of AI agents with **proper frontmatter definitions**:

```yaml
# .claude/agents/team-lead.md
---
name: team-lead
description: Orchestrates the agent team
model: sonnet
tools: [Read, Glob, Grep, TaskCreate, TaskUpdate, TaskList, TaskGet, SendMessage]
disallowedTools: [Write, Edit, Bash]
maxTurns: 50
effort: high
---
```

**Default Team:**

| Agent | Role | Can Edit Code? |
|-------|------|----------------|
| **Team Lead** | Orchestrates, assigns tasks (never writes code) | No |
| **Quality Agent** | Verifies RED/GREEN TDD phases, coverage >= 80% | No |
| **Security Agent** | OWASP scanning, secrets detection, dependency audit | No |
| **Code Review Agent** | Multi-engine reviews | No |
| **Merger Agent** | Creates feature branches and PRs via `gh` CLI | No |
| **Feature Agent (x N)** | One per feature, follows strict TDD pipeline | Yes |

**Pipeline (enforced by task dependencies):**

```
Spec > Spec Review > Tests > RED Verify > Implement >
GREEN Verify > Validate > Code Review > Security > Branch+PR
```

```bash
# Auto-spawned by /initialize-project, or manually:
/spawn-team
```

## What Gets Created

```
your-project/
├── .claude/
│   ├── agents/               # Agent definitions with frontmatter
│   │   ├── team-lead.md      # name, model, tools, disallowedTools, maxTurns
│   │   ├── quality.md
│   │   ├── security.md
│   │   ├── code-review.md
│   │   ├── merger.md
│   │   └── feature.md
│   ├── rules/                # Conditional rules (paths: frontmatter)
│   │   ├── quality-gates.md  # Always active
│   │   ├── tdd-workflow.md   # Always active
│   │   ├── security.md       # Always active
│   │   ├── react.md          # Active on .tsx/.jsx files
│   │   ├── typescript.md     # Active on .ts/.tsx files
│   │   ├── python.md         # Active on .py files
│   │   └── nodejs-backend.md # Active on api/routes/server files
│   ├── skills/               # Skills loaded via @include
│   │   ├── base/SKILL.md
│   │   ├── iterative-development/SKILL.md
│   │   ├── security/SKILL.md
│   │   ├── mnemos/SKILL.md
│   │   ├── cross-agent-delegation/SKILL.md
│   │   └── [framework]/SKILL.md
│   └── settings.json         # Permissions + hooks + statusline
├── scripts/
│   ├── tdd-loop-check.sh     # Stop hook script for TDD loops
│   ├── icpg/                 # Intent-Augmented Code Property Graph
│   └── mnemos/               # Task-Scoped Memory Lifecycle
├── .mnemos/                  # Mnemos state (auto-created, gitignored)
│   ├── mnemo.db              # SQLite MnemoGraph
│   ├── fatigue.json          # Live fatigue signal
│   ├── signals.jsonl         # Behavioral signal log
│   └── checkpoint-latest.json # Most recent checkpoint
├── .github/workflows/
│   ├── quality.yml
│   └── security.yml
├── _project_specs/
│   ├── features/
│   └── todos/
├── CLAUDE.md                 # @include directives, project context
└── CLAUDE.local.md           # Private developer overrides (gitignored)
```

## Commit Hygiene

```
┌─────────────────────────────────────────────────────────────┐
│  COMMIT SIZE THRESHOLDS                                     │
├─────────────────────────────────────────────────────────────┤
│  OK:     ≤ 5 files,  ≤ 200 lines                           │
│  WARN:   6-10 files, 201-400 lines  → "Commit soon"        │
│  STOP:   > 10 files, > 400 lines    → "Commit NOW"         │
└─────────────────────────────────────────────────────────────┘
```

## Skills Included (62 Skills)

### Core Skills
| Skill | Purpose |
|-------|---------|
| `base.md` | Universal patterns, constraints, TDD workflow, atomic todos |
| `iterative-development.md` | TDD loops via Stop hooks (replaces Ralph Wiggum) |
| `mnemos.md` | Task-scoped memory lifecycle — fatigue monitoring, checkpoints, typed compaction |
| `icpg.md` | Intent-augmented code property graph — track why code exists, detect drift |
| `code-review.md` | Mandatory code reviews - Claude, Codex, Gemini, or multi-engine |
| `codex-review.md` | OpenAI Codex CLI code review |
| `gemini-review.md` | Google Gemini CLI code review, 1M token context |
| `workspace.md` | Multi-repo workspace awareness, contract tracking |
| `commit-hygiene.md` | Atomic commits, PR size limits |
| `code-deduplication.md` | Prevent semantic duplication with capability index |
| `agent-teams.md` | Agent team workflow with proper frontmatter definitions |
| `ticket-craft.md` | AI-native ticket writing optimized for Claude Code |
| `maggy.md` | Optional local AI command center — AI-prioritized inbox, one-click TDD execute, competitor intelligence. See the [Maggy section](#maggy--ai-engineering-command-center-optional) for the full docs |
| `team-coordination.md` | Multi-person projects, shared state, handoffs |
| `code-graph.md` | Persistent code graph via MCP |
| `cpg-analysis.md` | Deep CPG analysis - Joern + CodeQL |
| `security.md` | OWASP patterns, secrets management |
| `credentials.md` | Centralized API key management |
| `session-management.md` | Context preservation, resumability |
| `project-tooling.md` | gh, vercel, supabase CLI + deployment |
| `existing-repo.md` | Analyze existing repos, setup guardrails |
| `cross-agent-delegation.md` | Cross-agent task routing, Codex auto-review, Kimi delegation |
| `polyphony.md` | Multi-agent orchestration with container-isolated workspaces |

### Language & Framework Skills
| Skill | Purpose |
|-------|---------|
| `python.md` | Python + ruff + mypy + pytest |
| `typescript.md` | TypeScript strict + eslint + jest |
| `nodejs-backend.md` | Express/Fastify patterns, repositories |
| `react-web.md` | React + hooks + React Query + Zustand |
| `react-native.md` | Mobile patterns, platform-specific code |
| `android-java.md` | Android Java with MVVM, ViewBinding, Espresso |
| `android-kotlin.md` | Android Kotlin with Coroutines, Jetpack Compose, Hilt |
| `flutter.md` | Flutter with Riverpod, Freezed, go_router |

### UI Skills
| Skill | Purpose |
|-------|---------|
| `ui-web.md` | Web UI - Tailwind, dark mode, accessibility |
| `ui-mobile.md` | Mobile UI - React Native, iOS/Android patterns |
| `ui-testing.md` | Visual testing |
| `playwright-testing.md` | E2E testing - Playwright, Page Objects |
| `user-journeys.md` | User experience flows |
| `pwa-development.md` | Progressive Web Apps - service workers, offline |

### Database & Backend Skills
| Skill | Purpose |
|-------|---------|
| `database-schema.md` | Schema awareness |
| `supabase.md` | Core Supabase CLI, migrations, RLS |
| `supabase-nextjs.md` | Next.js + Supabase + Drizzle ORM |
| `supabase-python.md` | FastAPI + Supabase |
| `supabase-node.md` | Express/Hono + Supabase |
| `firebase.md` | Firebase Firestore, Auth, Storage |
| `cloudflare-d1.md` | Cloudflare D1 SQLite with Workers |
| `aws-dynamodb.md` | AWS DynamoDB single-table design |
| `aws-aurora.md` | AWS Aurora Serverless v2 |
| `azure-cosmosdb.md` | Azure Cosmos DB |

### AI & Agentic Skills
| Skill | Purpose |
|-------|---------|
| `agentic-development.md` | Build AI agents |
| `llm-patterns.md` | AI-first apps, LLM testing |
| `ai-models.md` | Latest models reference |

### Content, Integration & Other Skills
| Skill | Purpose |
|-------|---------|
| `aeo-optimization.md` | AI Engine Optimization |
| `web-content.md` | SEO + AI discovery |
| `site-architecture.md` | Technical SEO |
| `web-payments.md` | Stripe Checkout, subscriptions |
| `reddit-api.md` | Reddit API |
| `reddit-ads.md` | Reddit Ads API + agentic optimization |
| `ms-teams-apps.md` | Microsoft Teams bots |
| `posthog-analytics.md` | PostHog analytics |
| `shopify-apps.md` | Shopify app development |
| `woocommerce.md` | WooCommerce REST API |
| `medusa.md` | Medusa headless commerce |
| `klaviyo.md` | Klaviyo email/SMS marketing |

## Usage Patterns

### New Project
```bash
mkdir my-new-app && cd my-new-app
claude
> /initialize-project
```

### Existing Project
```bash
cd my-existing-app
claude
> /initialize-project
# Auto-detects existing code → runs analysis first
```

### Update Skills Globally
```bash
cd "$(cat ~/.claude/.bootstrap-dir)"
git pull
./install.sh
```

## Prerequisites

```bash
# GitHub CLI
brew install gh && gh auth login

# Vercel CLI (optional)
npm i -g vercel && vercel login

# Supabase CLI (optional)
brew install supabase/tap/supabase && supabase login
```

## Evolution

| Version | Date | What Changed |
|---------|------|-------------|
| **v1.0** | Jan 2026 | Initial release — 30+ skills, `/initialize-project`, TDD via Ralph Wiggum loops, Python/TypeScript/React support |
| **v2.0** | Jan 2026 | Skills restructured (`folder/SKILL.md`), YAML frontmatter, validation tests, 60+ skills across 10 categories |
| **v3.0** | Mar 2026 | **Real Claude Code infrastructure** — Ralph Wiggum replaced with Stop hooks, `@include` directives, conditional rules (`paths:` frontmatter), agent teams via `.claude/agents/`, pre-configured permissions |
| **v3.3** | Apr 2026 | Mnemos (task-scoped memory), iCPG (intent tracking + drift detection), Maggy dashboard MVP (inbox, execute, competitors) |
| **v3.5** | Apr 2026 | PreCompact hook for smarter compaction, fatigue model (4 dimensions), hook error resilience |
| **v3.6** | May 2026 | Cross-tool compatibility (Claude + Kimi + Codex), cross-agent intelligence (Codex auto-review, Kimi delegation), complexity-based routing |
| **v4.0** | May 2026 | **Polyphony** — multi-agent orchestration with container isolation, 5-dimension complexity scoring, Docker runtime, 3 agent adapters, state machine task lifecycle |
| **v5.0** | May 2026 | **Autonomous command center** — Interactive Chat with `--resume` takeover, P2P Mesh networking, process intelligence, auto-bootstrap, grouped UI (Work/Intel/System), 468 tests, security hardening (path validation, streaming lock) |

### Where we started vs where we are

| Area | v1 (Jan 2026) | v5 (May 2026) |
|------|---------------|---------------|
| **Scope** | Claude Code project setup tool | Autonomous AI engineering platform |
| **TDD** | Ralph Wiggum plugin (didn't exist) | Real Stop hooks with iteration tracking |
| **Skills** | 30 flat `.md` files | 62 skills with `@include`, conditional rules |
| **Memory** | None (lost on compaction) | Mnemos typed graph + fatigue model |
| **Intent** | None | iCPG with 6-dimension drift detection |
| **Agents** | Single Claude session | Polyphony containers + cross-agent delegation |
| **Models** | Claude only | Claude + Codex + Kimi + complexity routing |
| **Dashboard** | None | Maggy — chat, tasks, competitors, insights, mesh |
| **Networking** | None | P2P Mesh (WebSocket sync, org-scoped) |
| **Tests** | Shell validation script | 468 pytest tests + integration suite |

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for version history.

## License

MIT - See [LICENSE](LICENSE)

## Credits

Built on learnings from 100+ projects across customer experience management, agentic AI platforms, mobile apps, and full-stack web applications.

---

**Need help scaling AI in your org?** [Claude Code & MCP experts](https://leanai.ventures/aiops/claude)


================================================
FILE: _project_specs/00-autonomous-engineering-roadmap.md
================================================
# Autonomous Engineering Roadmap

A set of specs closing the gaps between claude-bootstrap's current code-intelligence stack (`codebase-memory-mcp` + `iCPG` + `Joern/CodeQL` + `Mnemos` + `code-deduplication`) and what an autonomous coding agent actually needs to ship changes without supervision.

## Why these?

Autonomous agents fail in 10 specific, repeatable ways (see [comparison doc in chat history — 2026-04-20](#)). Our current stack addresses 9 of them. The specs below close the remaining agent-observable gaps and add the two "frontier" capabilities (multimodal ingestion, verifiable contracts).

## Priority order

**Tier 1 — highest leverage, unlocks the rest:**

| # | Spec | Why it matters |
|---|---|---|
| 01 | [Runtime observability](01-runtime-observability.md) | Drift detection is static — an agent that ships code needs a production feedback signal to know if the change actually worked |
| 03 | [Verifiable contracts](03-verifiable-contracts.md) | iCPG postconditions are currently natural-language. Generating property-based tests from them makes them machine-checkable. |
| 07 | [Human escalation protocol](07-human-escalation-protocol.md) | When the agent is stuck, it needs a formal "page a human with this packet" channel |

**Tier 2 — valuable, not blocking:**

| # | Spec | Why it matters |
|---|---|---|
| 08 | [Auto CODE_INDEX](08-auto-code-index.md) | The capability index currently depends on humans maintaining it. Auto-derive from the graph. |
| 04 | [Multi-agent coordination](04-multi-agent-coordination.md) | When two agents touch the same area, we need locking / negotiation |
| 02 | [Rollback & recovery](02-rollback-and-recovery.md) | Drift flags a problem; we still need automated revert paths |

**Tier 3 — frontier / optional:**

| # | Spec | Why it matters |
|---|---|---|
| 05 | [Confidence calibration](05-confidence-calibration.md) | Reinforcement loop — learn from past agent actions which patterns fail |
| 06 | [Cost / budget awareness](06-cost-budget-awareness.md) | Agents stuck in loops burn real money. Hard budget stops. |
| 09 | [Multimodal ingestion](09-multimodal-ingestion.md) | Graphify-style. Only matters if your repos include docs/images/video. |

## What each spec contains

- **Context** — the failure mode being addressed
- **Goal** — one-sentence outcome
- **Approach** — concrete integration points with existing skills/scripts
- **Success criteria** — how we know it works
- **Effort** — rough size (small / medium / large)
- **Depends on** — other specs that should land first

## Implementation convention

When picking up a spec:

1. Create a feature branch `feat/spec-XX-<short-slug>`
2. Add an entry to `CHANGELOG.md` under an "Unreleased" section
3. Write the feature following TDD (as the rest of the project does)
4. Update the spec file's `Status` field when merged

Status values: `pending` · `in-progress` · `in-review` · `done` · `deferred`


================================================
FILE: _project_specs/01-runtime-observability.md
================================================
# Spec 01: Runtime Observability for Drift Detection

**Status:** pending
**Priority:** Tier 1 (highest leverage)
**Effort:** Medium

## Context

`iCPG` detects drift **statically** — it can tell you a symbol's checksum changed, its tests disappeared, or a postcondition's predicate no longer holds against the current codebase. What it cannot tell you is whether the running system still delivers what the intent promised.

An autonomous agent that ships code needs a feedback signal after deploy. Otherwise:

- A refactor passes all tests and drift checks but tanks p99 latency in production → agent has no signal
- A bug fix validates against one invariant but introduces regressions users hit → silent
- An intent's postcondition is "<500ms response" — a static graph can't verify this

## Goal

Bridge `iCPG` to runtime telemetry so drift detection includes post-deploy signals, not just pre-commit signals.

## Approach

### Step 1 — Define a runtime-signal abstraction

Add a new edge type to iCPG:

```
VALIDATED_IN_PROD    Reason → Metric    (intent's postcondition has a runtime check)
```

A `Metric` node references an observability query:

```yaml
metric:
  id: "checkout_p99_under_500ms"
  source: "datadog"       # datadog | sentry | honeycomb | prometheus
  query: "avg:trace.checkout.latency.p99{env:prod}"
  predicate: "value < 500"
  window: "1h"
```

### Step 2 — Pluggable observability adapters

One-file adapters per backend (`scripts/icpg/observability/`):

- `datadog_adapter.py` — query API key from env, return metric value
- `sentry_adapter.py` — query event frequency for a given issue
- `honeycomb_adapter.py` — run a Honeycomb query and extract result
- `prometheus_adapter.py` — PromQL
- `stub_adapter.py` — for testing, reads from a JSON file

Each exposes `fetch(metric_id, window) -> float | None`.

### Step 3 — Extend `icpg drift check` with `--include-runtime`

When the flag is set, evaluate every `VALIDATED_IN_PROD` edge by calling its adapter. Runtime predicate failure adds a 7th drift dimension:

```
Runtime drift   Postcondition metric violates its predicate in production
```

### Step 4 — Hook into claude-bootstrap's post-commit flow

The `hooks/post-commit-graph` script runs `icpg record`. Add an optional `--check-runtime` step that queries the adapters for any symbols touched in this commit, so the agent sees drift before the change ships.

## Integration points

- `scripts/icpg/models.py` — add `MetricNode`, `RuntimeEdge`
- `scripts/icpg/drift.py` — add `check_runtime_drift()`
- `scripts/icpg/__main__.py` — wire `drift check --include-runtime` flag
- `skills/icpg/SKILL.md` — document the pattern
- `templates/icpg-metric.yaml` — template for declaring metrics

## Success criteria

1. `icpg drift check --include-runtime` queries configured adapters and reports runtime-dimension drift
2. At least one adapter (Datadog or Sentry) ships with docs + example config
3. A test harness using `stub_adapter` verifies runtime drift triggers correctly
4. Agent receives runtime signal in pre-task query output (`icpg query risk` includes current runtime state)
5. Zero network calls when no `VALIDATED_IN_PROD` edges exist — backward compatible

## Depends on

None — can be built independently on top of current iCPG.

## Follow-ups

- Spec 02 (rollback) uses the same signal to auto-revert on severe drift
- Spec 05 (confidence calibration) learns from runtime failures


================================================
FILE: _project_specs/02-rollback-and-recovery.md
================================================
# Spec 02: Rollback & Recovery

**Status:** pending
**Priority:** Tier 2
**Effort:** Medium

## Context

When `iCPG` detects drift or a runtime signal (Spec 01) indicates a shipped change broke something, the agent has no automated path to recover. It knows the problem exists but still has to manually coordinate a revert — find the right commit, check for downstream work, revert, re-verify.

For autonomous engineering this needs to be a first-class operation. The agent should be able to say "revert intent R-abc because its postcondition failed in production" and get a safe, auditable rollback.

## Goal

Add a `icpg revert` command that safely undoes all commits attributed to a given ReasonNode, handling downstream dependencies and leaving a verifiable audit trail.

## Approach

### Step 1 — Track commit SHAs on intents

iCPG already has `CREATES` / `MODIFIES` edges between ReasonNodes and Symbols. Extend the `record` command to also store the commit SHA that made the change:

```
CREATES      Reason → Symbol    [commit_sha, timestamp]
MODIFIES     Reason → Symbol    [commit_sha, timestamp]
```

### Step 2 — `icpg revert <intent-id>`

The command:

1. Collects all commit SHAs attributed to this intent (from its edges)
2. Checks for downstream `REQUIRES` intents whose postconditions depend on this one
3. If downstream intents exist and aren't in `drifted`/`abandoned` status → refuse revert, explain the chain
4. Otherwise: `git revert --no-commit <sha1> <sha2> ...` in reverse chronological order
5. Runs the intent's `VALIDATED_BY` tests to confirm pre-intent state is reached
6. Updates the intent status to `reverted` (new status)
7. Emits a `REVERTED` edge type linking the revert commit to the original

### Step 3 — Auto-revert on severe drift (opt-in)

Wire into drift detection: when `Runtime drift` severity > 0.9 AND drift age < 1h AND `auto_revert: true` is set on the intent → trigger `icpg revert` automatically and page a human (Spec 07).

Config per-project in `.icpg/config.yaml`:

```yaml
auto_revert:
  enabled: false        # opt-in per project
  severity_threshold: 0.9
  max_age_minutes: 60
  require_test_pass: true
```

### Step 4 — Recovery for partial failures

If `git revert` fails mid-way (conflicts, missing commits), leave the tree in a clean state (`git revert --abort`) and report exactly which commit failed + why.

## Integration points

- `scripts/icpg/__main__.py` — add `revert` subcommand
- `scripts/icpg/models.py` — add `commit_sha` field on edges, `reverted` status, `REVERTED` edge type
- `scripts/icpg/drift.py` — optional auto-revert trigger for severe runtime drift
- `hooks/post-commit-graph` — capture SHA when recording
- `skills/icpg/SKILL.md` — add revert section

## Success criteria

1. `icpg revert <id>` reverts all commits attributed to that intent cleanly or explains why it can't
2. Downstream `REQUIRES` intents block the revert with a clear message
3. Auto-revert is opt-in per-intent and only fires on high-severity runtime drift
4. Every revert is logged in the graph with `REVERTED` edges pointing to the original commits
5. A test harness verifies revert correctness against a scripted intent lifecycle

## Depends on

- Spec 01 (runtime observability) — the auto-revert signal comes from runtime drift


================================================
FILE: _project_specs/03-verifiable-contracts.md
================================================
# Spec 03: Verifiable Contracts (Property-Based Test Generation)

**Status:** pending
**Priority:** Tier 1 (highest leverage)
**Effort:** Large

## Context

iCPG's ReasonNodes already carry formal contracts:

```
preconditions:   What must be true before execution
postconditions:  What must be true when fulfilled
invariants:      What must remain true
```

Today these are natural-language strings. Drift detection matches commit patterns and checksums against them heuristically. That's good but not verifiable — the agent can't prove a postcondition still holds after a change.

For autonomous engineering, we want machine-checkable contracts: the agent writes a postcondition, and the system generates tests that will fail if the postcondition is ever violated.

## Goal

Generate property-based tests from iCPG postconditions so drift detection becomes "did the test pass?" instead of "does the string still plausibly match?"

## Approach

### Step 1 — Structured postconditions (optional schema)

Let authors write postconditions in either natural language (current) or a structured form that's machine-generatable:

```yaml
postconditions:
  - type: "returns"
    of: "save_response"
    shape: "Response"
    properties:
      - "response.id is not null"
      - "response.org_id == input.org_id"
      - "len(response.answers) == len(input.answers)"
  - type: "invariant"
    holds: "during_save"
    assertion: "db.responses.count() increases by 1"
```

The structured form compiles to tests; natural language fallback uses LLM-assisted generation (Step 2).

### Step 2 — Pluggable property-based test generators

One generator per language/framework:

- `scripts/icpg/codegen/hypothesis_python.py` — Hypothesis (Python)
- `scripts/icpg/codegen/fastcheck_ts.py` — fast-check (TypeScript)
- `scripts/icpg/codegen/proptest_rust.py` — proptest (Rust)
- Natural-language postconditions use LLM generation, structured ones compile directly

Each takes a `ReasonNode` and returns a test file with a `# @icpg-generated from R-abc123` header so the agent knows not to hand-edit.

### Step 3 — `icpg contracts generate <intent-id>`

CLI command that:

1. Reads the intent's postconditions
2. Detects the language of the scope files (already tracked)
3. Invokes the right generator
4. Writes tests to `tests/generated/contracts/<intent-id>.test.py` (or equivalent)
5. Adds a `VALIDATED_BY` edge automatically

`icpg contracts generate --all` regenerates every intent's tests (bulk operation for upgrading existing projects).

### Step 4 — Drift check gains a "contract-verified" signal

Existing drift detection checks whether `VALIDATED_BY` tests exist and pass. With this spec, those tests are now *derived from the postconditions* rather than hand-written, so failure is a direct postcondition violation signal — not just "a test broke."

### Step 5 — Regenerate on intent edit

When a ReasonNode's postconditions change, stale generated tests are flagged. Agent can run `icpg contracts sync` to regenerate; humans can review the diff.

## Integration points

- `scripts/icpg/models.py` — add structured `postcondition` variants alongside existing strings
- `scripts/icpg/codegen/` — new package, one module per language/framework
- `scripts/icpg/__main__.py` — `contracts generate`, `contracts sync` subcommands
- `skills/icpg/SKILL.md` — document how to write structured postconditions
- `templates/reasonnode-structured.yaml` — template showing both forms

## Success criteria

1. Given an intent with structured postconditions, `icpg contracts generate` produces a runnable property-based test in Hypothesis/fast-check
2. The generated test has a header marking it as machine-generated
3. Running the test suite fails immediately when a postcondition is violated in the actual implementation
4. Natural-language postconditions fall back to LLM generation cleanly (doesn't silently skip)
5. Drift detection differentiates "stale test" from "postcondition violation" in its severity score

## Depends on

None (iCPG only). But pairs well with:

- Spec 01 — runtime postconditions (metric predicates) complement code-level postconditions
- Spec 02 — a generated test failure is a strong auto-revert signal


================================================
FILE: _project_specs/04-multi-agent-coordination.md
================================================
# Spec 04: Multi-Agent Coordination (Symbol-Level Locks)

**Status:** pending
**Priority:** Tier 2
**Effort:** Medium

## Context

claude-bootstrap already has `agent-teams` and `team-coordination` skills, and Maggy ships with a P2P session-handoff pattern. But when two agents (or two sessions of the same agent) want to modify the same area of code, there's no coordination protocol. First-to-commit wins, which creates silent merge conflicts, duplicated work, and lost intent tracking.

For autonomous engineering at team scale (multiple agents, or one agent coordinating long-running subtasks), we need intent-level and symbol-level locks.

## Goal

Agents claim exclusive work on an intent or set of symbols before modifying, negotiate with holders of conflicting locks, and release on completion or timeout.

## Approach

### Step 1 — Lock primitive in iCPG

Add a `lock` table and edge type:

```
LOCKED_BY    Reason | Symbol → Agent    [acquired_at, expires_at, purpose]
```

Locks are scoped to an intent (broadest), a set of files, or a set of symbols (finest). A lock has:

- `holder_id` — agent or session identifier
- `scope` — intent id | files[] | symbols[]
- `purpose` — one-line description ("refactor auth service")
- `acquired_at` / `expires_at` — auto-expire to prevent orphans (default 30 min)
- `heartbeat_at` — renewed periodically by the holder

### Step 2 — `icpg lock` / `icpg unlock` commands

```bash
icpg lock intent R-abc --purpose "refactor auth" --expires 30m
icpg lock symbols auth.login,auth.logout --purpose "rate-limiting fix"
icpg locks list                              # show all active locks
icpg unlock R-abc                             # release
icpg locks prune                              # remove expired
```

Lock attempts on a held scope return the holder's info so the requesting agent can decide what to do (wait, negotiate, defer).

### Step 3 — Pre-task query integration

Extend the 3 canonical pre-task queries with a 4th:

| Query | What It Answers |
|---|---|
| `icpg query locks <scope>` | Is someone else working on this right now? |

The PreToolUse hook adds this to the injected context before any Edit/Write call.

### Step 4 — Negotiation protocol

When an agent wants a held lock, it sends a `negotiation_request` to the holder (Mnemos message):

- Requester states: intent, priority, estimated duration
- Holder responds: `accept` (release), `defer` (hold until completion), `split` (narrow the lock to specific symbols)

If no response within 5 minutes, the requester either takes the lock (if the holder's heartbeat is stale) or escalates (Spec 07).

### Step 5 — Conflict prevention at commit time

Post-commit hook verifies the committing agent holds the right lock for all symbols the commit modified. If not, the commit is logged as `unauthorized_modification` and the drift check flags it.

## Integration points

- `scripts/icpg/models.py` — `Lock`, `LockedByEdge`
- `scripts/icpg/store.py` — `acquire_lock`, `release_lock`, `prune_locks`, `list_locks`
- `scripts/icpg/__main__.py` — `lock`, `unlock`, `locks` subcommands
- `hooks/pre-tool-use` — inject active-lock context
- `hooks/post-commit-graph` — verify lock matches modified symbols
- `skills/agent-teams/SKILL.md` — add locking discipline section
- `skills/icpg/SKILL.md` — document the 4th pre-task query

## Success criteria

1. Two concurrent agents attempting to modify the same symbol can't both succeed — the second sees the held lock
2. Locks auto-expire 30 min after last heartbeat (agents don't have to remember to release)
3. Pre-task queries include active-lock info
4. Commits violating lock ownership are flagged in drift reports
5. Negotiation protocol works: requester gets a structured response from holder, or escalation fires

## Depends on

- Spec 07 (escalation) — when negotiation fails, escalation fires
- Builds on existing `agent-teams` and Maggy P2P patterns


================================================
FILE: _project_specs/05-confidence-calibration.md
================================================
# Spec 05: Confidence Calibration (Reinforcement Loop)

**Status:** pending
**Priority:** Tier 3 (frontier)
**Effort:** Medium

## Context

iCPG's `get_risk_profile` query today classifies symbols as fragile/stable based on ownership history and drift count. It doesn't learn from what actually failed when agents touched it. An agent that tried refactoring this file three times and failed gets the same risk score as one that hasn't been tried yet.

For autonomous engineering, we want a reinforcement loop: past agent failures against a symbol or pattern should raise its risk score for future agents.

## Goal

Track agent actions and their outcomes against symbols/patterns, and use that history to calibrate confidence for future pre-task queries.

## Approach

### Step 1 — Action-outcome tracking

Add two new node types to iCPG:

```
AgentAction   { id, agent, intent, scope[], timestamp }
Outcome       { action_id, result, evidence }
```

Result types:
- `success` — tests passed, intent fulfilled, no drift
- `partial` — intent fulfilled but introduced drift elsewhere
- `failure_test` — tests failed, rolled back
- `failure_runtime` — shipped, runtime drift detected (Spec 01)
- `abandoned` — agent gave up

Evidence is a pointer — commit SHA, test output, drift report.

### Step 2 — Hook into existing flows

Automatic capture:

- Pre-task query writes an open `AgentAction` node
- Post-commit: matches to the most recent pending action and records outcome based on test results
- Drift check: if a `VALIDATED_BY` test fails on an intent, the agent action tied to that intent's commit is marked `failure_test`
- Spec 01 runtime drift: marks `failure_runtime`
- Spec 02 auto-revert: marks `abandoned`

### Step 3 — Risk score now includes success rate

`icpg query risk <symbol>` returns a calibrated score:

```
Historical success rate for this symbol: 40% (2 of 5 attempts successful)
Pattern complexity: high (10+ dependents, 3 owners, drifted twice)
Recommendation: treat as fragile — consider smaller changes or pair
```

Calibration uses a simple Bayesian update: prior = structural risk (current method), likelihood = recent action outcomes.

### Step 4 — Pattern-level learning (stretch)

For autonomous agents, single-symbol history is too narrow — we want "refactors of dataclasses with >5 fields fail 60% of the time." This requires clustering actions by pattern, not just symbol. Defer this to a v2 of this spec; first ship the single-symbol version.

### Step 5 — Privacy & data hygiene

Action history is sensitive (could leak intent details). Make it:

- Opt-out per project (`.icpg/config.yaml: track_outcomes: false`)
- Redact content, keep structure only (symbol ids, outcome types, timestamps)
- Never exported outside the `.icpg/` directory

## Integration points

- `scripts/icpg/models.py` — `AgentAction`, `Outcome` node types
- `scripts/icpg/store.py` — outcome-tracking tables
- `scripts/icpg/drift.py` — risk scoring gains history term
- `hooks/pre-tool-use` — record `AgentAction` before Edit/Write calls
- `hooks/post-commit-graph` — finalize the outcome
- `skills/icpg/SKILL.md` — document calibrated risk semantics

## Success criteria

1. Every agent Edit/Write action is automatically logged (no manual reporting)
2. `icpg query risk <symbol>` returns a score incorporating historical outcomes
3. Risk score converges toward structural risk when action history is empty (no regression)
4. Privacy opt-out works — no history written when disabled
5. A test harness replays an action sequence and verifies calibrated scores update correctly

## Depends on

- Spec 01 (runtime observability) — feeds `failure_runtime` signal
- Spec 02 (rollback) — feeds `abandoned` signal
- Spec 03 (verifiable contracts) — feeds high-signal `failure_test` from postcondition failures


================================================
FILE: _project_specs/06-cost-budget-awareness.md
================================================
# Spec 06: Cost / Budget Awareness

**Status:** pending
**Priority:** Tier 3 (frontier)
**Effort:** Small

## Context

Autonomous agents stuck in loops burn real money. Mnemos's fatigue detection (4-dim: tokens, scatter, re-reads, error density) is a *behavioral* proxy for "the agent is struggling" but it isn't a hard stop. An agent that's actually wasting tokens or API calls needs a budget ceiling.

This matters especially for:

- `/improve-maggy`, self-improvement flows, anything that spawns subagents
- Team runs where one misbehaving agent shouldn't bankrupt the whole run
- Maggy's TDD execute pipeline (up to 3 Claude Code invocations per ticket)

## Goal

Add per-task and per-session budget limits with hard stops and a budget-aware fatigue state.

## Approach

### Step 1 — Declare a budget in intent config

Extend ReasonNode:

```yaml
budget:
  tokens: 100000
  api_calls: 50
  wall_clock_minutes: 30
  usd: 5.00
```

All fields optional. `usd` calculated from model pricing tables (current Sonnet/Opus rates, refreshed quarterly).

### Step 2 — Track spend via hooks

PostToolUse hook accumulates:

- Tokens consumed (from `transcript_path` JSON blobs)
- Claude API calls (by counting tool uses)
- Wall clock elapsed since intent started

Stored in `.icpg/budgets/<intent-id>.json` with heartbeats.

### Step 3 — Budget-aware fatigue state

Add a 5th Mnemos fatigue dimension: `budget_burn_rate`. If the agent has consumed 70% of its token budget at 40% progress, that's a signal to compress / consolidate / consider abandoning. Threshold behavior:

| Budget consumed | Action |
|---|---|
| <60% | Normal |
| 60-85% | Mnemos COMPRESS state forced |
| 85-100% | Mnemos REM state forced, agent warned to wrap up |
| >100% | Hard stop — PreToolUse hook rejects further Edit/Write/Bash |

### Step 4 — Graceful stop behavior

When budget is exceeded:

1. PreToolUse hook returns `budget_exceeded` error with context about remaining work
2. Agent is expected to write a handoff Mnemos checkpoint before exiting
3. Intent status flips to `deferred_budget`
4. Human (or another agent with a fresh budget) can resume from the checkpoint

### Step 5 — Budget override

A human can set `allow_overage: true` on an intent or raise the limit mid-run. Override requires a commit to the intent's config (auditable).

## Integration points

- `scripts/icpg/models.py` — `Budget` field on ReasonNode
- `scripts/icpg/budget.py` — new module for tracking and enforcement
- `hooks/pre-tool-use` — budget check before Edit/Write/Bash
- `hooks/post-tool-use` — accumulate spend
- `templates/pricing.yaml` — model → $/token table, refreshed quarterly
- `skills/mnemos/SKILL.md` — document the 5th fatigue dimension
- `skills/icpg/SKILL.md` — document budget declaration

## Success criteria

1. An intent with a 10k-token budget hard-stops at 10k tokens via PreToolUse rejection
2. Mnemos fatigue state reflects budget consumption (COMPRESS / REM / EMERGENCY)
3. Budget overruns leave a Mnemos handoff checkpoint so work can resume
4. `icpg budgets list` shows current spend vs limit per active intent
5. No budget declared → no enforcement (backward compatible)

## Depends on

- Mnemos fatigue model (already exists)
- Nothing else


================================================
FILE: _project_specs/07-human-escalation-protocol.md
================================================
# Spec 07: Human-in-the-Loop Escalation Protocol

**Status:** pending
**Priority:** Tier 1 (highest leverage)
**Effort:** Small-Medium

## Context

When an autonomous agent hits a wall it can't resolve — drift it can't fix, a contract violation with no clear cause, lock negotiation failure, budget exceeded — there's no formal protocol for raising the problem to a human. The hooks infrastructure exists, the discipline doesn't.

Today the agent might:
- Silently continue and compound the issue
- Write a confused summary and exit, leaving no actionable packet
- Page every minor issue, creating alert fatigue

None of these scale to autonomous engineering at a team level.

## Goal

A standard escalation protocol: the agent packages a context packet (what it tried, what went wrong, what it needs a human to decide) and delivers it through a configured channel.

## Approach

### Step 1 — Escalation packet schema

```yaml
escalation:
  id: "esc-abc123"
  agent: "claude-opus-4.7"
  intent: "R-auth-refactor"
  severity: "blocking"           # blocking | high | medium | low
  category: "drift_unresolvable" # or: contract_violation, lock_conflict,
                                 # budget_exceeded, taint_detected, unknown
  summary: "Two-sentence description of the situation"
  what_was_tried:
    - "Attempted X — result: failed because Y"
    - "Attempted Z — result: partial"
  proposed_options:
    - "Option A: revert to sha abc, human makes a decision"
    - "Option B: accept the drift, update postcondition"
  context_refs:
    - "commit: sha-latest"
    - "intent: R-auth-refactor"
    - "drift_report: path/to/drift.json"
    - "mnemos_checkpoint: path/to/checkpoint.json"
  awaiting: "resolution"
```

### Step 2 — `icpg escalate` CLI

```bash
icpg escalate --intent R-auth-refactor \
              --category drift_unresolvable \
              --severity blocking \
              --summary "Cannot resolve postcondition drift" \
              --context drift.json
```

Writes the packet to `.icpg/escalations/<id>.yaml` and fires the configured delivery channel.

### Step 3 — Pluggable delivery channels

One adapter per channel (`scripts/icpg/escalation/`):

- `slack_adapter.py` — post to configured channel with packet fields
- `github_issue_adapter.py` — create issue with the packet
- `email_adapter.py` — SendGrid / SMTP
- `file_adapter.py` — default; writes to `.icpg/escalations/` only (for local/dev)

Config in `.icpg/config.yaml`:

```yaml
escalation:
  channels:
    - type: slack
      webhook_url_env: SLACK_ESCALATION_WEBHOOK
      min_severity: high
    - type: github_issue
      repo: "org/repo"
      min_severity: blocking
```

### Step 4 — Auto-trigger from known conditions

Wire automatic escalations:

| Condition | Severity | Category |
|---|---|---|
| Drift severity >0.8, auto-revert failed | blocking | drift_unresolvable |
| Contract violation caught by generated test (Spec 03) | high | contract_violation |
| Lock negotiation timeout (Spec 04) | medium | lock_conflict |
| Budget exceeded without handoff checkpoint (Spec 06) | high | budget_exceeded |
| CodeQL finds new taint path | blocking | taint_detected |

Each hook module calls `icpg escalate` with the right packet when its trigger fires.

### Step 5 — Resolution tracking

When a human responds (comment on the GitHub issue, Slack thread reply with a resolution marker like `resolved: revert`), an `EscalationResolution` node is written and any pending agent waiting on the packet can resume.

Agents consult `icpg escalations list --pending` as part of their pre-task queries.

### Step 6 — Rate limiting / dedup

Don't spam. If the same intent + category has an open escalation, merge into it (append to `what_was_tried`) instead of creating a new one. Escalation adapter respects a per-channel rate limit.

## Integration points

- `scripts/icpg/models.py` — `Escalation`, `EscalationResolution`
- `scripts/icpg/escalation/` — new package, one module per channel
- `scripts/icpg/__main__.py` — `escalate`, `escalations list/resolve` subcommands
- `hooks/post-tool-use` — auto-escalate on trigger conditions
- `skills/icpg/SKILL.md` — document when agents should manually call it
- `templates/escalation-config.yaml` — example config

## Success criteria

1. Agent can manually escalate a situation with `icpg escalate` and humans receive it through at least one channel (Slack preferred)
2. Auto-escalations fire for all 5 trigger conditions above
3. Dedup works — same intent + category doesn't spam
4. Human resolution flows back as `EscalationResolution` node, pending agents can detect it
5. Local/dev config uses file-only adapter (no external calls), never breaks tests

## Depends on

None directly — builds on existing hook infrastructure. Integrates with:
- Spec 02 (rollback) — failed auto-revert triggers escalation
- Spec 03 (contracts) — test failures trigger escalation
- Spec 04 (locks) — negotiation timeout triggers escalation
- Spec 06 (budget) — overrun without handoff triggers escalation


================================================
FILE: _project_specs/08-auto-code-index.md
================================================
# Spec 08: Auto-Derived CODE_INDEX from Graph

**Status:** pending
**Priority:** Tier 2
**Effort:** Small-Medium

## Context

The `code-deduplication` skill requires a `CODE_INDEX.md` in the project root — a capability index that tells the agent "this already exists, don't reimplement it." The current design asks humans (or agents) to maintain it manually.

In practice:

- Agents don't reliably update the index when they add capabilities
- Humans forget to update it
- The index drifts from reality fast
- Agents that check the index get stale info and duplicate anyway

Since we already have `codebase-memory-mcp` (symbol graph) and `iCPG` (intent graph), we can derive the capability index from them instead of hand-maintaining it.

## Goal

Auto-generate `CODE_INDEX.md` from the graph, refreshed on every commit, organized by capability so agents can check-before-write reliably.

## Approach

### Step 1 — Capability extraction pass

A new pass over the combined graph:

1. Read all `ReasonNode`s with status `fulfilled` (iCPG)
2. For each, pull the symbols they `CREATE` or `MODIFY`
3. Group by capability domain (inferred from:
   - intent's `scope` path prefixes — `app/auth/*` → "auth"
   - intent's `decision_type` — `business_goal` and `arch_decision` are top-level, `task` and `workaround` are subcategories
   - common tag patterns in the codebase)
4. For each capability, collect the main entry points (public classes/functions that serve that capability)

### Step 2 — Emit CODE_INDEX.md

```markdown
# Code Capability Index

Auto-generated from iCPG + codebase-memory-mcp. Last updated: 2026-04-20.
Run `icpg index build` to regenerate.

## Authentication
**Capability:** user auth, session management, token handling
**Entry points:**
- `app.auth.login_user()` [app/auth/login.py:42] — primary login
- `app.auth.session.SessionManager` [app/auth/session.py] — session lifecycle
**Intents:** R-auth-base, R-jwt-refactor, R-rate-limit

## Survey responses
**Capability:** create, validate, persist, query survey responses
**Entry points:** ...
```

Output is deterministic — same graph state produces the same output.

### Step 3 — Hook into post-commit

Every commit that records new iCPG edges triggers a regeneration. Runs in under a second for typical repo sizes since it's a DB scan + markdown emit.

### Step 4 — `icpg index` subcommand

```bash
icpg index build        # regenerate CODE_INDEX.md
icpg index check        # verify CODE_INDEX.md matches graph state (for CI)
icpg index query auth   # query a specific capability section
```

The `check` subcommand lets CI reject commits that leave an out-of-sync CODE_INDEX.

### Step 5 — Agent workflow integration

The `code-deduplication` skill's pre-write discipline stays the same, but the data source changes from "human-maintained CODE_INDEX.md" to "graph-derived CODE_INDEX.md." Update the skill to:

1. Call `icpg query prior "<goal>"` (iCPG's existing prior-work query)
2. If no match, consult the index sections matching the intent's scope
3. Only create new code if both checks are dry

Also add `icpg query capability "<description>"` — a semantic search over capability descriptions in the index, not just symbol names.

### Step 6 — Keep hand-written sections (optional)

Let humans add non-derived sections (architecture notes, business domain glossary) in a separate file — `CODE_INDEX.human.md` — and `icpg index build` appends it. Auto-derived + human annotations cleanly separated.

## Integration points

- `scripts/icpg/index.py` — new module, grouping + emit logic
- `scripts/icpg/__main__.py` — `index build`, `index check`, `index query` subcommands
- `hooks/post-commit-graph` — call `icpg index build`
- `skills/code-deduplication/SKILL.md` — update to reference auto-derived index
- `templates/CODE_INDEX.md` — deprecate the hand-maintained template; add note pointing to the auto-generated path

## Success criteria

1. On any repo with iCPG populated, `icpg index build` produces a grouped, readable CODE_INDEX.md
2. `icpg index check` detects drift between graph and markdown (for CI)
3. Agents find existing capabilities via semantic search (`icpg query capability "rate limiting"`)
4. Generation is deterministic — same graph → same markdown
5. Backward compatible: projects without iCPG continue to hand-maintain; projects with iCPG get the auto version
6. Regeneration is <2s on a 10k-symbol repo

## Depends on

- iCPG (required)
- codebase-memory-mcp (preferred — used for richer capability grouping)


================================================
FILE: _project_specs/09-multimodal-ingestion.md
================================================
# Spec 09: Multimodal Ingestion (Optional Graphify-Style Extension)

**Status:** pending
**Priority:** Tier 3 (frontier / optional)
**Effort:** Large

## Context

Our stack is code-only. Some repos carry essential context in non-code artifacts:

- Product specs in PDFs or Google Docs exports
- Architecture diagrams in PNG / Miro / whiteboard photos
- Engineering demos in MP4
- Research papers in PDF

When an autonomous agent works on such a repo, it currently ignores these artifacts. That's a real gap — the agent makes code decisions without knowing the intent captured in the diagrams or docs.

Graphify (github.com/safishamsi/graphify) solves this: it ingests docs, images, audio, and video into the same knowledge graph as code. We don't need to rebuild their work — we can adopt their approach as an optional extension to claude-bootstrap.

**This spec is optional** — only valuable if your repos actually carry non-code context. Most don't.

## Goal

Let claude-bootstrap ingest non-code artifacts into the iCPG graph so agents can reason about code + docs + images in the same queries.

## Approach

### Step 1 — Artifact node type

Extend iCPG with a new node:

```
Artifact {
  id, path, kind, content_hash, ingested_at,
  extracted_concepts: []    // concept strings
}
```

Kinds: `pdf`, `markdown`, `image`, `diagram`, `video`, `audio`, `slides`.

### Step 2 — Ingestion pipeline

`icpg ingest <path>` — one command, pluggable extractors:

- `pdf_extractor.py` — text via `pypdf` or `pdfplumber`, then LLM to extract key concepts
- `markdown_extractor.py` — parse headings, blockquotes, pull out "key decision" patterns
- `image_extractor.py` — Claude multimodal: "describe this diagram; list entities and relationships"
- `video_extractor.py` — `faster-whisper` transcription with domain-aware prompt, then concept extraction
- `audio_extractor.py` — same as video, skip video decode

Each extractor emits concept nodes + relationships back into iCPG using the existing edge vocabulary:
- `DESCRIBES` — Artifact → Symbol / Reason (this doc describes this code)
- `MENTIONS` — Artifact → Concept (looser reference)
- `DECIDES` — Artifact → Reason (this doc made an architectural decision that became an intent)

### Step 3 — `.icpgignore` for ingest paths

Respect a per-project `.icpgignore` like graphify's `.graphifyignore`, using `.gitignore` syntax. Default excludes: `node_modules/`, `dist/`, `.venv/`, `*.generated.*`, binary builds.

### Step 4 — Incremental refresh

Track content hashes per artifact. Re-ingest only when hash changes. Bulk re-ingest via `icpg ingest --refresh`.

### Step 5 — Extend pre-task queries

Add a 5th canonical query:

```bash
icpg query docs "<topic>"   # Find artifacts relevant to this topic
```

Returns: artifact paths, extracted concepts, relationships to code symbols.

The PreToolUse hook includes this in the injected context when the agent is about to write code in a scope touched by `DESCRIBES` edges.

### Step 6 — Transparent honesty about inference

Adopt graphify's `EXTRACTED` / `INFERRED` / `AMBIGUOUS` edge labeling. PDF text → EXTRACTED. Image concept → INFERRED with confidence. Whiteboard smudged text → AMBIGUOUS, flagged for review.

### Step 7 — Cost control

LLM-based extractors (images, video transcripts) are expensive. Respect Spec 06 budgets. `icpg ingest` without a budget flag runs only the free extractors (markdown, PDF text). Image / video / audio require `--enable-llm` explicit flag.

### Step 8 — Distribution

Ship this as a **separate installable package** — `claude-bootstrap-multimodal` on PyPI. Base claude-bootstrap stays code-only. Users opt in:

```bash
pip install claude-bootstrap-multimodal
icpg ingest docs/ specs/
```

## Integration points

- `scripts/icpg/models.py` — `Artifact`, new edge types (`DESCRIBES`, `MENTIONS`, `DECIDES`)
- `scripts/icpg/ingest/` — new package (could live in a separate repo)
- `scripts/icpg/__main__.py` — `ingest` subcommand
- `skills/icpg/SKILL.md` — document the 5th pre-task query
- `skills/multimodal/SKILL.md` — new skill describing when to use ingestion

## Success criteria

1. `icpg ingest docs/` processes markdown + PDF without LLM and creates artifact nodes
2. `icpg ingest --enable-llm specs/` processes images and videos, with the budget flag respected
3. Pre-task queries surface relevant documentation when the agent is about to modify code touched by `DESCRIBES` edges
4. Re-ingestion only processes changed files (hash-based cache)
5. Base claude-bootstrap doesn't require multimodal deps to work — installed separately

## Depends on

- Spec 06 (budget) — LLM extractors must respect budget caps

## Alternative: adopt graphify directly

Instead of building this, we could document "for multimodal, run graphify alongside" and provide a conversion tool that imports graphify's `graph.json` into iCPG as Artifact nodes. This is faster to ship and avoids duplicating graphify's work.

**Recommendation:** ship the conversion tool first (1-2 days of work), observe adoption, build native ingestion only if real demand emerges.


================================================
FILE: commands/analyze-repo.md
================================================
# Analyze Repository

Analyze an existing repository's structure, conventions, and guardrails.

**This command runs automatically** when `/initialize-project` detects an existing codebase without Claude setup. You can also run it standalone anytime.

**Use this command standalone when:**
- You want to re-analyze after making changes
- You want analysis without running `/initialize-project`
- Auditing code quality and guardrails on any repo
- Reviewing a codebase without adding Claude skills

**Automatic trigger:**
- `/initialize-project` on existing codebase → auto-runs this analysis first

---

## Phase 1: Repository Detection

Run these checks to understand the repo:

```bash
# Git info
echo "=== Git Status ===" && \
git remote -v 2>/dev/null && \
git branch -a 2>/dev/null | head -10 && \
git log --oneline -5 2>/dev/null

# Config files
echo "=== Config Files ===" && \
ls -la *.json *.toml *.yaml *.yml 2>/dev/null

# Directory structure (3 levels, excluding noise)
echo "=== Directory Structure ===" && \
find . -type d -maxdepth 3 \
    -not -path "*/node_modules/*" \
    -not -path "*/.git/*" \
    -not -path "*/venv/*" \
    -not -path "*/__pycache__/*" \
    -not -path "*/dist/*" \
    -not -path "*/build/*" \
    2>/dev/null | head -40
```

---

## Phase 2: Tech Stack Detection

Identify the primary technologies:

```bash
# JavaScript/TypeScript
if [ -f "package.json" ]; then
    echo "=== Package.json ===" && \
    cat package.json | head -50
fi

# Python
if [ -f "pyproject.toml" ]; then
    echo "=== pyproject.toml ===" && \
    cat pyproject.toml
fi

# Mobile
ls pubspec.yaml android/build.gradle ios/*.xcodeproj 2>/dev/null
```

Based on findings, determine:

| File | Technology |
|------|------------|
| package.json + tsconfig.json | TypeScript |
| package.json (no tsconfig) | JavaScript |
| pyproject.toml | Python |
| pubspec.yaml | Flutter (Dart) |
| android/build.gradle | Android Native |
| Cargo.toml | Rust |
| go.mod | Go |

---

## Phase 3: Repo Structure Type

Classify the repository:

```bash
# Check structure type
echo "=== Repo Structure Type ===" && \
if [ -d "packages" ] || [ -d "apps" ] || grep -q '"workspaces"' package.json 2>/dev/null; then
    echo "MONOREPO - Multiple packages/apps with shared tooling"
elif [ -d "frontend" ] && [ -d "backend" ]; then
    echo "FULL-STACK MONOLITH - Frontend + Backend in same repo"
elif [ -d "src" ] && grep -q '"react\|vue\|angular"' package.json 2>/dev/null; then
    echo "FRONTEND - Single frontend application"
elif [ -d "src" ] && grep -q '"express\|fastify\|koa"' package.json 2>/dev/null; then
    echo "BACKEND - Single backend application"
elif [ -f "pyproject.toml" ] && grep -q "fastapi\|django\|flask" pyproject.toml 2>/dev/null; then
    echo "BACKEND (Python) - Single backend application"
else
    echo "STANDARD - Single-purpose repository"
fi
```

---

## Phase 4: Guardrails Audit

Check existing code quality tools:

```bash
echo "=== Guardrails Audit ===" && \

# Pre-commit hooks
echo "Pre-commit Hooks:" && \
[ -d ".husky" ] && echo "  [x] Husky installed" || echo "  [ ] Husky NOT installed" && \
[ -f ".pre-commit-config.yaml" ] && echo "  [x] pre-commit framework" || echo "  [ ] pre-commit framework NOT installed" && \
[ -f ".git/hooks/pre-commit" ] && echo "  [x] Git hooks present" || echo "  [ ] No git hooks"

# Linting
echo "Linting:" && \
(grep -q '"eslint"' package.json 2>/dev/null && echo "  [x] ESLint") || \
(grep -q '"biome"' package.json 2>/dev/null && echo "  [x] Biome") || \
(grep -q "ruff" pyproject.toml 2>/dev/null && echo "  [x] Ruff") || \
echo "  [ ] No linter detected"

# Formatting
echo "Formatting:" && \
(grep -q '"prettier"' package.json 2>/dev/null && echo "  [x] Prettier") || \
(grep -q "black" pyproject.toml 2>/dev/null && echo "  [x] Black") || \
(grep -q "ruff" pyproject.toml 2>/dev/null && echo "  [x] Ruff (formatting)") || \
echo "  [ ] No formatter detected"

# Type checking
echo "Type Checking:" && \
([ -f "tsconfig.json" ] && echo "  [x] TypeScript") || \
(grep -q "mypy" pyproject.toml 2>/dev/null && echo "  [x] mypy") || \
(grep -q "pyright" pyproject.toml 2>/dev/null && echo "  [x] pyright") || \
echo "  [ ] No type checker detected"

# Testing
echo "Testing:" && \
(grep -q '"jest\|vitest"' package.json 2>/dev/null && echo "  [x] Jest/Vitest") || \
(grep -q "pytest" pyproject.toml 2>/dev/null && echo "  [x] pytest") || \
echo "  [ ] No test framework detected"

# Commit validation
echo "Commit Validation:" && \
([ -f "commitlint.config.js" ] && echo "  [x] commitlint") || \
(grep -q "conventional-pre-commit" .pre-commit-config.yaml 2>/dev/null && echo "  [x] conventional-pre-commit") || \
echo "  [ ] No commit validation"

# CI/CD
echo "CI/CD:" && \
[ -d ".github/workflows" ] && echo "  [x] GitHub Actions" || echo "  [ ] No GitHub Actions" && \
[ -f ".gitlab-ci.yml" ] && echo "  [x] GitLab CI" || true && \
[ -f "Jenkinsfile" ] && echo "  [x] Jenkins" || true
```

---

## Phase 5: Convention Detection

Identify existing code patterns:

```bash
echo "=== Convention Detection ===" && \

# File naming
echo "File Naming:" && \
ls src/**/*.ts 2>/dev/null | head -5 && \
ls src/**/*.py 2>/dev/null | head -5

# Import style (JS/TS)
echo "Import Style:" && \
grep -h "^import" src/**/*.ts 2>/dev/null | head -5

# Export style (JS/TS)
echo "Export Style:" && \
grep -h "^export" src/**/*.ts 2>/dev/null | head -5

# Test file location
echo "Test Location:" && \
find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*.py" 2>/dev/null | head -5
```

---

## Phase 6: Generate Report

Based on all findings, generate this report structure:

```markdown
# Repository Analysis Report

**Generated:** [timestamp]
**Repository:** [name from git remote or directory]

## Overview

| Attribute | Value |
|-----------|-------|
| Type | [Monorepo / Full-Stack / Frontend / Backend] |
| Language | [TypeScript / Python / ...] |
| Framework | [React / FastAPI / ...] |
| Package Manager | [npm / pnpm / uv / pip] |

## Directory Structure

[Simplified tree output]

## Tech Stack

| Category | Technology | Config |
|----------|------------|--------|
| Language | X | X |
| Framework | X | X |
| Testing | X | X |
| Linting | X | X |
| Formatting | X | X |

## Guardrails Status

### Present
- [x] Item 1
- [x] Item 2

### Missing (Recommended to Add)
- [ ] Item 1 - [brief reason]
- [ ] Item 2 - [brief reason]

## Conventions Observed

| Pattern | Observed Value | Example |
|---------|----------------|---------|
| Naming | camelCase / snake_case | file.ts |
| Imports | Absolute / Relative | @/components |
| Tests | Colocated / Separate | *.test.ts |
| Exports | Named / Default | export { X } |

## Recommendations

1. **High Priority**
   - [Recommendation with reason]

2. **Medium Priority**
   - [Recommendation with reason]

3. **Low Priority / Nice to Have**
   - [Recommendation with reason]

## Key Files to Review

| File | Purpose | Why Review |
|------|---------|------------|
| src/index.ts | Entry point | Understand app bootstrap |
| src/config.ts | Configuration | Understand env handling |
| tests/setup.ts | Test setup | Understand test patterns |
```

---

## Phase 7: Offer Next Steps

After generating the report, offer these options:

> **Analysis complete!** Here's what I found: [summary]
>
> What would you like to do next?
> 1. **Add missing guardrails** - Set up pre-commit hooks, linting, etc.
> 2. **Generate detailed conventions doc** - Document patterns for team
> 3. **Set up Claude integration** - Run `/initialize-project` to add Claude skills
> 4. **Start working on code** - I'll follow the conventions I detected
> 5. **Something else**

---

## Quick Analysis (One Command)

For a quick overview without the full report:

```bash
echo "=== Quick Analysis ===" && \
echo "Repo: $(basename $(pwd))" && \
echo "Type: $([ -d packages ] && echo 'Monorepo' || ([ -d frontend ] && [ -d backend ] && echo 'Full-Stack') || echo 'Standard')" && \
echo "Tech: $([ -f package.json ] && echo 'JS/TS' || ([ -f pyproject.toml ] && echo 'Python') || echo 'Other')" && \
echo "Guardrails: $([ -d .husky ] || [ -f .pre-commit-config.yaml ] && echo 'Present' || echo 'Missing')" && \
echo "CI/CD: $([ -d .github/workflows ] && echo 'GitHub Actions' || echo 'None')"
```


================================================
FILE: commands/analyze-workspace.md
================================================
# /analyze-workspace

> Full dynamic analysis of workspace topology, dependencies, and contracts.

## Trigger

Run this command when:
- First time setting up workspace awareness
- Major refactor or new module added
- Weekly scheduled refresh
- `/sync-contracts` reports too much drift
- Switching to work on a different workspace

## Behavior

### Phase 1: Topology Discovery (~30 seconds)

```
🔍 Analyzing workspace topology...

Checking workspace indicators:
  ✓ Found turbo.json (Turborepo)
  ✓ Found pnpm-workspace.yaml
  ✗ No nx.json
  ✗ No lerna.json

Workspace type: Monorepo (Turborepo)
Root: /Users/ali/code/myapp

Discovering modules...
  ✓ apps/web (package.json found)
  ✓ apps/api (pyproject.toml found)
  ✓ packages/shared-types (package.json found)
  ✓ packages/db (package.json found)

Modules found: 4
```

### Phase 2: Module Analysis (~60 seconds)

For each module, analyze:

```
📦 Analyzing apps/web...
  Tech stack: Next.js 14, TypeScript, TailwindCSS
  Entry point: src/app/layout.tsx
  Key directories: src/lib/, src/components/, src/types/
  Dependencies: @repo/shared-types, @repo/ui
  External calls: fetch → apps/api (15 files)
  Token estimate: 18K full, 5K summarized

📦 Analyzing apps/api...
  Tech stack: FastAPI, Python 3.12, SQLAlchemy
  Entry point: app/main.py
  Key directories: app/routes/, app/schemas/, app/models/
  Dependencies: packages/db (internal)
  Exposes: OpenAPI spec (47 endpoints)
  Token estimate: 24K full, 7K summarized

📦 Analyzing packages/shared-types...
  Tech stack: TypeScript
  Entry point: src/index.ts
  Exports: 34 types
  Consumed by: apps/web, apps/api (codegen)
  Token estimate: 3K

📦 Analyzing packages/db...
  Tech stack: Drizzle ORM, TypeScript
  Entry point: src/index.ts
  Tables: 12
  Migrations: 23
  Token estimate: 8K full, 2K schema only
```

### Phase 3: Contract Extraction (~45 seconds)

```
📜 Extracting contracts...

OpenAPI Detection:
  ✓ apps/api/openapi.json (47 endpoints, 23 schemas)

GraphQL Detection:
  ✗ No GraphQL schemas found

TypeScript Types:
  ✓ packages/shared-types/src/index.ts (34 exports)

Pydantic Schemas:
  ✓ apps/api/app/schemas/ (23 models)

Database Schema:
  ✓ packages/db/schema/ (12 tables)

Contract sources registered: 5 files
```

### Phase 4: Dependency Graph (~30 seconds)

```
🔗 Building dependency graph...

Internal dependencies:
  apps/web → packages/shared-types (23 imports)
  apps/web → apps/api (15 API calls)
  apps/api → packages/db (12 imports)
  apps/api → packages/shared-types (codegen)
  packages/db → (none)
  packages/shared-types → (none)

Dependency order (for changes):
  1. packages/shared-types (leaf)
  2. packages/db (leaf)
  3. apps/api (depends on db, shared-types)
  4. apps/web (depends on api, shared-types)
```

### Phase 5: Key File Identification (~30 seconds)

```
📁 Identifying key files...

High priority (always relevant):
  ✓ apps/api/openapi.json
  ✓ packages/shared-types/src/index.ts
  ✓ apps/web/src/lib/api/client.ts

Context-specific:
  ✓ API work: apps/api/app/routes/*.py
  ✓ DB work: packages/db/schema/*.ts
  ✓ Auth work: apps/api/app/routes/auth.py + deps
  ✓ Frontend: apps/web/src/components/**

Token budget by context:
  Frontend API: ~8K tokens
  Backend endpoints: ~12K tokens
  Database changes: ~6K tokens
  Shared types: ~4K tokens
```

### Phase 6: Generate Artifacts

```
📝 Generating workspace artifacts...

Created:
  ✓ _project_specs/workspace/TOPOLOGY.md
  ✓ _project_specs/workspace/CONTRACTS.md
  ✓ _project_specs/workspace/DEPENDENCY_GRAPH.md
  ✓ _project_specs/workspace/KEY_FILES.md
  ✓ _project_specs/workspace/CROSS_REPO_INDEX.md
  ✓ _project_specs/workspace/.contract-sources
```

## Final Output

```
════════════════════════════════════════════════════════════════
  WORKSPACE ANALYSIS COMPLETE
════════════════════════════════════════════════════════════════

Workspace: myapp
Type: Monorepo (Turborepo)
Modules: 4 (2 apps, 2 packages)

┌─────────────────────────────────────────────────┐
│ apps/web (Next.js) ←──── apps/api (FastAPI)     │
│      │                        │                 │
│      ▼                        ▼                 │
│ packages/shared-types    packages/db            │
└─────────────────────────────────────────────────┘

Contracts:
  REST API: 47 endpoints
  Shared types: 34 interfaces
  DB tables: 12

Token Estimates:
  Current module only: ~20K tokens
  With cross-module context: ~45K tokens
  Full workspace: ~53K tokens
  Budget remaining: ~100K tokens ✓

Artifacts generated in: _project_specs/workspace/

Next steps:
  • Contracts will auto-sync on commit (if changed)
  • Run /sync-contracts manually to refresh
  • Run /workspace-status for quick check

════════════════════════════════════════════════════════════════
```

## Flags

| Flag | Description |
|------|-------------|
| `--force` | Regenerate all artifacts even if recent |
| `--type <type>` | Override auto-detection: `monorepo`, `multi-repo`, `hybrid` |
| `--repos <paths>` | For multi-repo: comma-separated paths to related repos |
| `--skip-contracts` | Skip contract extraction (faster) |
| `--verbose` | Show detailed analysis output |
| `--json` | Output as JSON (for tooling) |

## Multi-Repo Mode

For workspaces with separate git repositories:

```bash
# Auto-detect sibling repos
/analyze-workspace --type multi-repo

# Specify repo locations explicitly
/analyze-workspace --type multi-repo --repos "../backend,../shared,../mobile"
```

Claude will:
1. Detect related repos in parent directory
2. Set up symlinks in `.workspace/repos/` if needed
3. Analyze each repo
4. Build cross-repo dependency graph
5. Extract contracts from each

## Integration Points

### On First Run

Creates the full workspace context structure:

```
_project_specs/
└── workspace/
    ├── TOPOLOGY.md
    ├── CONTRACTS.md
    ├── DEPENDENCY_GRAPH.md
    ├── KEY_FILES.md
    ├── CROSS_REPO_INDEX.md
    ├── .contract-sources
    └── cache/              # Cached cross-repo files
```

### Updates CLAUDE.md

Adds workspace skill reference:

```markdown
## Skills
- .claude/skills/workspace.md
```

### Sets Up Hooks

Installs contract freshness hooks:
- Session start: Staleness check
- Post-commit: Auto-sync trigger
- Pre-push: Validation gate

## Error Handling

### No Workspace Detected

```
⚠️  No workspace configuration detected

This appears to be a single-repo project.
Use /analyze-repo for single repository analysis.

Or specify workspace type manually:
  /analyze-workspace --type monorepo
  /analyze-workspace --type multi-repo --repos "../other-repo"
```

### Access Denied to Related Repo

```
⚠️  Cannot access related repository: ../backend

Options:
  1. Ensure the repo exists at that path
  2. Create symlink: ln -s /path/to/backend .workspace/repos/backend
  3. Skip this repo: /analyze-workspace --skip-repo backend
```

### Contract Extraction Failed

```
⚠️  Failed to extract contracts from apps/api

Reason: openapi.json not found

Suggestions:
  1. Generate OpenAPI spec: cd apps/api && python -m app.generate_openapi
  2. Skip contract extraction: /analyze-workspace --skip-contracts
  3. Use inferred contracts: /analyze-workspace --infer-contracts
```

## When to Re-run

| Scenario | Action |
|----------|--------|
| Added new module/package | Full `/analyze-workspace` |
| Changed API endpoints | `/sync-contracts` (lightweight) |
| Major refactor | Full `/analyze-workspace --force` |
| Weekly maintenance | Full `/analyze-workspace` |
| Quick check | `/workspace-status` |


================================================
FILE: commands/check-contributors.md
================================================
# Check Contributors

Checks who's working on the project and optionally converts to a multi-person project with team state management.

---

## What This Command Does

1. **Detect current state** - Is this a solo or team project?
2. **Show active contributors** - Who's working on what right now?
3. **Offer conversion** - Convert solo → team project if needed

---

## Phase 1: Detect Project Type

Check for team structure:

```bash
# Check if team coordination exists
ls _project_specs/team/state.md 2>/dev/null
ls _project_specs/team/contributors.md 2>/dev/null

# Check git contributors
git shortlog -sn --all 2>/dev/null | head -10

# Check recent activity
git log --oneline --since="7 days ago" --format="%an" | sort | uniq -c | sort -rn
```

### If Team Structure Exists

Report current state:

```
📊 Team Project Detected

Contributors:
┌──────────┬────────────────┬──────────┐
│ Handle   │ Focus Area     │ Status   │
├──────────┼────────────────┼──────────┤
│ @alice   │ Backend, Auth  │ 🟢 Active │
│ @bob     │ Frontend       │ 🟡 Paused │
└──────────┴────────────────┴──────────┘

Active Sessions:
• @alice working on TODO-042 (src/auth/*)
• No conflicts detected

Claimed Todos:
• TODO-042 - @alice (since 2024-01-15)
• TODO-038 - @bob (since 2024-01-14)

Recent Decisions:
• [2024-01-15] JWT vs Sessions - chose JWT (@alice)

Run 'cat _project_specs/team/state.md' for full details.
```

### If Solo Project

```
👤 Solo Project Detected

Git contributors found:
• alice@example.com (142 commits)
• bob@example.com (38 commits)  ← Recent activity

This project has multiple git contributors but no team coordination.

Would you like to:
1. Convert to team project (adds team state management)
2. Keep as solo project (no changes)
```

---

## Phase 2: Convert to Team Project

If user chooses to convert:

### Step 1: Create Team Structure

```bash
mkdir -p _project_specs/team/handoffs
```

### Step 2: Create state.md

```markdown
# Team State

*Last synced: [TIMESTAMP]*

## Active Sessions

| Contributor | Working On | Started | Files Touched | Status |
|-------------|------------|---------|---------------|--------|
| - | - | - | - | - |

## Claimed Todos

| Todo | Claimed By | Since | ETA |
|------|------------|-------|-----|
| - | - | - | - |

## Recently Completed (Last 48h)

| Todo | Completed By | When | PR |
|------|--------------|------|-----|
| - | - | - | - |

## Conflicts to Watch

| Area | Contributors | Notes |
|------|--------------|-------|
| - | - | - |

## Announcements

- [DATE] Project converted to team coordination mode
```

### Step 3: Create contributors.md

Ask user about team members:

```
Who are the team members? (I'll help you fill this out)

For each person, I need:
- Handle (e.g., @alice)
- Name
- Focus areas (e.g., Backend, Auth)
- Timezone
- Status (Active/Part-time)
```

Then create:

```markdown
# Contributors

## Team Members

| Handle | Name | Focus Areas | Timezone | Status |
|--------|------|-------------|----------|--------|
| @[handle] | [name] | [areas] | [tz] | Active |

## Ownership

| Area | Primary | Backup | Notes |
|------|---------|--------|-------|
| - | - | - | Define as you work |

## Communication

- Slack: #[channel]
- PRs: Tag area owner for review
```

### Step 4: Update active.md

Add claim annotation format to existing todos:

```markdown
<!--
TEAM PROJECT - Claim format:
**Claimed:** @handle (YYYY-MM-DD HH:MM TZ)

Always claim a todo before starting work.
Check team/state.md for who's working on what.
-->

## [TODO-XXX] Description

**Status:** pending
**Claimed:** -

...
```

### Step 5: Update CLAUDE.md

Add team-coordination.md to skills list:

```markdown
## Skills
Read and follow these skills before writing any code:
- .claude/skills/base.md
- .claude/skills/team-coordination.md  ← Add this
...
```

### Step 6: Copy Skill

```bash
cp ~/.claude/skills/team-coordination.md .claude/skills/
```

---

## Phase 3: Summary

After conversion:

```
✅ Converted to Team Project

Created:
• _project_specs/team/state.md
• _project_specs/team/contributors.md
• _project_specs/team/handoffs/
• .claude/skills/team-coordination.md

Updated:
• _project_specs/todos/active.md (added claim format)
• CLAUDE.md (added team-coordination skill)

Next steps:
1. Fill out contributors.md with your team
2. Each team member should read team-coordination.md
3. Claim todos before starting work
4. Update state.md at start/end of each session

Commit these changes:
  git add _project_specs/team .claude/skills/team-coordination.md CLAUDE.md
  git commit -m "Enable team coordination for multi-person project"
  git push origin main
```

---

## Quick Check Mode

For quick status without conversion prompt:

```
/check-contributors --status
```

Output:

```
📊 Quick Status

Type: Team Project / Solo Project
Contributors: 3 (2 active this week)
Active Now: @alice (TODO-042)
Claimed: 2 todos
Conflicts: None

Last state update: 2 hours ago
```

---

## Reverting to Solo

If team coordination is no longer needed:

```
/check-contributors --solo
```

This:
1. Archives `_project_specs/team/` to `_project_specs/team-archive-[date]/`
2. Removes claim annotations from todos
3. Removes team-coordination.md from CLAUDE.md skills
4. Keeps decisions.md (valuable history)

---

## Usage

```bash
# Check who's working and see options
/check-contributors

# Quick status only
/check-contributors --status

# Force conversion to team project
/check-contributors --team

# Revert to solo project
/check-contributors --solo
```


================================================
FILE: commands/icpg-bootstrap.md
================================================
# /icpg-bootstrap — Bootstrap from Git History

Infer ReasonNodes from existing git commit history. One-time setup for existing codebases.

---

## Usage

`/icpg-bootstrap [--days N]`

Default: 90 days of history.

---

## Steps

### 1. Initialize iCPG if needed

```bash
icpg init
```

### 2. Run bootstrap

```bash
icpg bootstrap --days 90 --verbose
```

If no LLM API key available:
```bash
icpg bootstrap --days 90 --verbose --no-llm
```

### 3. Show results

```
iCPG BOOTSTRAP COMPLETE
═══════════════════════

History scanned: {N} days ({M} commits)
Commit clusters: {K}
ReasonNodes created: {R}
Symbols linked: {S}
Duplicates skipped: {D}

TOP INFERRED INTENTS:
  1. [0.80] "Add JWT authentication" — 12 symbols, 5 files
  2. [0.75] "Refactor payment processing" — 8 symbols, 3 files
  3. [0.65] "Fix rate limiting bug" — 3 symbols, 2 files
  ...

LOW CONFIDENCE (review recommended):
  - [0.55] "Update dependencies" — may be too generic
  - [0.50] "Misc fixes" — commit message unclear
```

### 4. Offer review

Ask the user:
> {N} ReasonNodes were inferred from git history.
> {M} are low-confidence and may need review.
>
> Would you like to:
> 1. Keep all (proceed with current quality)
> 2. Review low-confidence intents (I'll show each one)
> 3. Run drift scan now (`icpg drift check`)

### 5. Post-bootstrap drift scan

```bash
icpg drift check
```

Show any immediate drift detected.


================================================
FILE: commands/icpg-drift.md
================================================
# /icpg-drift — Show All Drift

Run a full drift scan and display all unresolved drift events, grouped by dimension and sorted by severity.

---

## Usage

`/icpg-drift`

---

## Steps

### 1. Run drift scan

```bash
icpg drift check
```

### 2. Also show existing unresolved drift

```bash
icpg status
```

### 3. Display results

```
DRIFT REPORT
═══════════════

{N} unresolved drift events across {M} symbols

BY SEVERITY:
  [0.85] spec(0.9) + decision(0.8) — validateToken drifted from "JWT auth"
  [0.60] ownership(0.7) + test(0.5) — UserService has 4 owners, tests stale
  ...

BY DIMENSION:
  Spec drift:       {count} events
  Decision drift:   {count} events
  Ownership drift:  {count} events
  Test drift:       {count} events
  Usage drift:      {count} events
  Dependency drift: {count} events

TOP ACTIONS:
  1. Fix spec drift in validateToken — checksum changed without MODIFIES edge
  2. Add tests for UserService — VALIDATED_BY tests are missing
  3. Assign single owner to PaymentProcessor — 5 different owners
```

### 4. Offer resolution

For each event, suggest:
- `icpg drift resolve <id>` to mark resolved
- Create a new MODIFIES ReasonNode if the change was intentional
- Write missing tests if test drift detected


================================================
FILE: commands/icpg-impact.md
================================================
# /icpg-impact — Show Blast Radius

Show the blast radius of a ReasonNode or symbol — what depends on it, what breaks if it changes.

---

## Usage

`/icpg-impact <id-or-symbol>`

- If argument looks like a UUID (contains `-`), treat as ReasonNode ID
- Otherwise, treat as symbol name and find its creating ReasonNode

---

## Steps

### 1. Resolve target

```bash
# If ReasonNode ID
icpg query blast <id>

# If symbol name
icpg query risk <symbol-name>
# Then get the creating reason from the output
icpg query blast <creating-reason-id>
```

### 2. Display results

Format the output as:

```
BLAST RADIUS: <goal>
═══════════════════════════════════

Symbols ({N}):
  function validateToken (src/auth/service.ts)
  class AuthMiddleware (src/auth/middleware.ts)
  ...

Dependent Intents ({N}):
  a1b2c3d4 — Dashboard user session management
  e5f6g7h8 — Payment authorization flow
  ...

Contracts:
  INV: file_exists("src/auth/middleware.ts")
  POST: test_exists("src/auth/__tests__/service.test.ts")

Risk: {HIGH|MEDIUM|LOW} based on dependent count + drift history
```

### 3. Recommendations

If high risk (>5 dependents or active drift):
- Suggest running full test suite before changes
- Suggest creating a new ReasonNode with MODIFIES edge
- Warn about function signatures to preserve


================================================
FILE: commands/icpg-why.md
================================================
# /icpg-why — Why Does This Code Exist?

Trace any symbol back to its creating ReasonNode — show the original goal, who wrote it, and whether it's still doing what it was made for.

---

## Usage

`/icpg-why <symbol-name>`

---

## Steps

### 1. Find the symbol

```bash
icpg query risk <symbol-name>
```

If not found, search more broadly:
```bash
icpg query context <likely-file-path>
```

### 2. Show the full trace

```
WHY: <symbol-name>
═══════════════════

Symbol: <type> <name> (<file-path>)
Signature: <signature>
Checksum: <checksum>

CREATING INTENT:
  ID: <reason-id>
  Goal: <goal>
  Type: <decision_type>
  Owner: <owner>
  Status: <status>
  Created: <date>

CONTRACTS:
  PRE: <preconditions>
  POST: <postconditions>
  INV: <invariants>

MODIFICATION HISTORY:
  1. <date> — <modifying-reason-goal> (by <owner>)
  2. <date> — <modifying-reason-goal> (by <owner>)

DRIFT STATUS: {CLEAN | DRIFTED}
  Dimensions: <drift-dimensions if any>
  Severity: <score>
```

### 3. If no ReasonNode found

Symbol exists but has no iCPG tracking:
```
⚠ No ReasonNode found for <symbol-name>.
This code has no tracked intent — consider creating one:
  icpg create "<inferred goal>" --scope <file>
```


================================================
FILE: commands/initialize-project.md
================================================
# Initialize Project

Full project setup with Claude coding guardrails. Works for both new and existing projects.

**This command is idempotent** - run it anytime to update skills, add missing structure, or reconfigure.

---

## Phase 0: Validate Bootstrap Installation

**FIRST**, verify Maggy is properly installed:

```bash
# Read bootstrap directory (saved during install)
BOOTSTRAP_DIR=$(cat ~/.claude/.bootstrap-dir 2>/dev/null)
# Run quick validation
"$BOOTSTRAP_DIR/tests/validate-structure.sh" --quick
```

This checks:
- Skills are installed with correct structure (folder/SKILL.md)
- Commands are installed (~/.claude/commands/)
- Hooks are installed (~/.claude/hooks/)

**If validation fails:**
- Show the error to user
- Suggest running: `cd "$BOOTSTRAP_DIR" && git pull && ./install.sh`
- Offer to continue anyway or abort

**If validation passes:**
- Continue to Phase 1

---

## Phase 1: Detect Project State

First, check what already exists:

```bash
# Check for existing Claude setup
ls -la .claude/skills/ 2>/dev/null
ls -la CLAUDE.md 2>/dev/null
ls -la _project_specs/ 2>/dev/null

# Check for cross-tool setup (Kimi CLI, Codex CLI)
ls -la .kimi/skills/ 2>/dev/null
ls -la .codex/skills/ 2>/dev/null
ls -la .agents/skills/ 2>/dev/null
ls -la AGENTS.md 2>/dev/null

# Detect installed AI CLI tools
BOOTSTRAP_DIR=$(cat ~/.claude/.bootstrap-dir 2>/dev/null)
DETECTED_AGENTS=$("$BOOTSTRAP_DIR/scripts/detect-agents.sh" 2>/dev/null || echo "claude")
echo "Detected AI CLI tools: $DETECTED_AGENTS"

# Check for existing git repo
git remote -v 2>/dev/null

# Check for existing package files
ls package.json pyproject.toml 2>/dev/null

# Check for Flutter project
ls pubspec.yaml 2>/dev/null

# Check for Android project
ls android/build.gradle android/app/build.gradle 2>/dev/null

# Check for native language in Android projects
find android -name "*.java" -type f 2>/dev/null | head -1
find android -name "*.kt" -type f 2>/dev/null | head -1
```

Based on findings, determine:
- **New project**: No CLAUDE.md, no .claude/skills/, no code files
- **Existing project with skills**: Has .claude/skills/ - offer to UPDATE
- **Existing codebase without skills**: Has code but no Claude setup - **AUTO-RUN ANALYSIS**

Inform the user:
- "Detected new project - will do full setup"
- "Detected existing Claude project - will update skills and add any missing structure"
- "Detected existing codebase - **analyzing before making changes...**"

**For existing codebases without Claude setup, AUTOMATICALLY proceed to Phase 1b.**

---

## Phase 1b: Analyze Existing Codebase (Auto-triggered)

**This phase runs automatically when an existing codebase is detected without Claude setup.**

### Step 1: Repository Structure Detection

```bash
echo "=== Analyzing Repository Structure ===" && \

# Detect repo type
if [ -d "packages" ] || [ -d "apps" ] || grep -q '"workspaces"' package.json 2>/dev/null; then
    REPO_TYPE="MONOREPO"
elif [ -d "frontend" ] && [ -d "backend" ]; then
    REPO_TYPE="FULL_STACK"
elif [ -d "src" ] && grep -q '"react\|vue\|angular"' package.json 2>/dev/null; then
    REPO_TYPE="FRONTEND"
elif [ -f "pyproject.toml" ] || grep -q '"express\|fastify"' package.json 2>/dev/null; then
    REPO_TYPE="BACKEND"
else
    REPO_TYPE="STANDARD"
fi
echo "Repo Type: $REPO_TYPE"

# Directory structure (3 levels, excluding noise)
find . -type d -maxdepth 3 \
    -not -path "*/node_modules/*" \
    -not -path "*/.git/*" \
    -not -path "*/venv/*" \
    -not -path "*/__pycache__/*" \
    -not -path "*/dist/*" \
    -not -path "*/build/*" \
    2>/dev/null | head -30
```

### Step 2: Tech Stack Detection

```bash
echo "=== Tech Stack ===" && \

# Primary language/framework
[ -f "package.json" ] && echo "JavaScript/TypeScript project"
[ -f "tsconfig.json" ] && echo "  → TypeScript configured"
[ -f "pyproject.toml" ] && echo "Python project"
[ -f "pubspec.yaml" ] && echo "Flutter project"
[ -d "android" ] && echo "Android project"

# Frameworks (from package.json)
if [ -f "package.json" ]; then
    grep -q '"react"' package.json && echo "  → React"
    grep -q '"next"' package.json && echo "  → Next.js"
    grep -q '"express"' package.json && echo "  → Express"
    grep -q '"fastify"' package.json && echo "  → Fastify"
fi

# Frameworks (from pyproject.toml)
if [ -f "pyproject.toml" ]; then
    grep -q "fastapi" pyproject.toml && echo "  → FastAPI"
    grep -q "django" pyproject.toml && echo "  → Django"
    grep -q "flask" pyproject.toml && echo "  → Flask"
fi
```

### Step 3: Guardrails Audit

```bash
echo "=== Guardrails Status ===" && \

# Pre-commit hooks
echo "Pre-commit Hooks:"
[ -d ".husky" ] && echo "  ✓ Husky installed" || echo "  ✗ Husky NOT installed"
[ -f ".pre-commit-config.yaml" ] && echo "  ✓ pre-commit framework" || echo "  ✗ pre-commit NOT installed"

# Linting
echo "Linting:"
(grep -q '"eslint"' package.json 2>/dev/null && echo "  ✓ ESLint") || \
(grep -q "ruff" pyproject.toml 2>/dev/null && echo "  ✓ Ruff") || \
echo "  ✗ No linter detected"

# Formatting
echo "Formatting:"
(grep -q '"prettier"' package.json 2>/dev/null && echo "  ✓ Prettier") || \
(grep -q "ruff\|black" pyproject.toml 2>/dev/null && echo "  ✓ Ruff/Black") || \
echo "  ✗ No formatter detected"

# Type checking
echo "Type Checking:"
([ -f "tsconfig.json" ] && echo "  ✓ TypeScript") || \
(grep -q "mypy" pyproject.toml 2>/dev/null && echo "  ✓ mypy") || \
echo "  ✗ No type checker detected"

# Commit validation
echo "Commit Validation:"
([ -f "commitlint.config.js" ] && echo "  ✓ commitlint") || \
(grep -q "conventional-pre-commit" .pre-commit-config.yaml 2>/dev/null && echo "  ✓ conventional-pre-commit") || \
echo "  ✗ No commit validation"

# CI/CD
echo "CI/CD:"
[ -d ".github/workflows" ] && echo "  ✓ GitHub Actions" || echo "  ✗ No GitHub Actions"
```

### Step 4: Convention Detection

```bash
echo "=== Conventions Detected ===" && \

# File naming pattern
echo "File Naming:"
ls src/**/*.ts 2>/dev/null | head -3 || ls src/**/*.py 2>/dev/null | head -3

# Import style
echo "Import Style:"
grep -h "^import" src/**/*.ts 2>/dev/null | head -3 || \
grep -h "^from\|^import" src/**/*.py 2>/dev/null | head -3

# Test location
echo "Test Location:"
[ -d "tests" ] && echo "  Separate tests/ directory"
[ -d "__tests__" ] && echo "  __tests__/ directory"
find . -name "*.test.*" -o -name "*.spec.*" 2>/dev/null | head -1 && echo "  Colocated tests"
```

### Step 5: Generate Analysis Summary

After running the analysis, present this summary to the user:

```markdown
## Repository Analysis Complete

**Type:** [Monorepo | Full-Stack | Frontend | Backend | Standard]
**Language:** [TypeScript | Python | Flutter | ...]
**Framework:** [React | FastAPI | ...]

### Guardrails Status

| Category | Status | Recommendation |
|----------|--------|----------------|
| Pre-commit hooks | ✗ Missing | Add Husky (JS) or pre-commit (Python) |
| Linting | ✓ ESLint | - |
| Formatting | ✗ Missing | Add Prettier |
| Type checking | ✓ TypeScript | - |
| Commit validation | ✗ Missing | Add commitlint |

### Conventions I'll Follow
- File naming: camelCase
- Imports: Absolute (@/...)
- Tests: Colocated (*.test.ts)
```

### Step 6: Present Options

After showing the analysis, ask:

> **I've analyzed this codebase. Here's what I found:** [summary above]
>
> What would you like me to do?
> 1. **Add Claude skills only** - Add skills, preserve everything else
> 2. **Add skills + missing guardrails** - Also setup Husky/pre-commit, commitlint, etc.
> 3. **Full setup** - Skills, guardrails, project specs structure, CI/CD
> 4. **Just show analysis** - Don't change anything yet

**Based on user choice:**
- Option 1 → Skip to Phase 4, only copy skills
- Option 2 → Phase 4 + guardrails setup from `existing-repo` skill
- Option 3 → Full Phase 4 execution
- Option 4 → End here, user can run `/initialize-project` again later

---

## Phase 2: Validate CLI Tools

Check required CLI tools are installed and authenticated:

```bash
# Check GitHub CLI
gh auth status

# Check Vercel CLI
vercel whoami

# Check Supabase CLI
supabase projects list
```

If any tool fails, inform the user and offer to skip:
- "GitHub CLI not authenticated. Run: `gh auth login` (or skip if not using GitHub)"
- "Vercel CLI not authenticated. Run: `vercel login` (or skip if not using Vercel)"
- "Supabase CLI not authenticated. Run: `supabase login` (or skip if not using Supabase)"

---

## Phase 3: Project Questions

**For existing projects with CLAUDE.md**: Read existing config first, then ask what to update.

**For new or unconfigured projects**: Ask these questions one at a time:

### 1. What are you building?
Ask for a brief description (1-2 sentences).
*Skip if CLAUDE.md exists and has Project Overview - show current and ask if they want to update.*

### 2. What language/runtime?
- Python
- TypeScript
- JavaScript (Node)
- Android Java
- Android Kotlin
- Flutter (Dart)
- Multiple (specify which)

*Auto-detect from package.json, pyproject.toml, pubspec.yaml, or android/ directory if present.*

### 3. What type of project?
- Backend API
- Frontend Web (React)
- Mobile App (React Native)
- Mobile App (Android Native)
- Mobile App (Flutter)
- Mobile App (Flutter + Native Android)
- Full Stack (Backend + Frontend)
- CLI Tool
- Library/Package

*Auto-detect from dependencies if possible.*

### 4. Is this an AI-first application?
- Yes (LLMs handle core logic)
- No (traditional application)

*Check for anthropic/openai in dependencies.*

### 4b. Code graph analysis level?
- **Standard** (default) - Lightweight AST graph with symbol lookup, dependency analysis, blast radius
- **Deep analysis** - Also enable Joern CPG (control flow, data flow, dead code detection)
- **Security audit** - Also enable CodeQL (taint analysis, vulnerability detection)
- **Full** - All three tiers

*Tier 1 (codebase-memory-mcp) is always enabled for all projects. This question determines opt-in tiers.*
*Auto-suggest: If security skill is included, suggest "Security audit". If AI-first, suggest "Deep analysis".*

### 5. What framework? (based on previous answers)
**Backend:**
- Python: FastAPI, Flask, Django
- Node: Express, Fastify, Hono

**Frontend Web:**
- React (Vite, Next.js)

**Mobile:**
- React Native, Expo

*Auto-detect from dependencies.*

### 6. What database?
- Supabase (Postgres)
- None / SQLite
- Other (specify)

*Skip if supabase/ directory exists.*

### 7. Where will this be deployed?
- Vercel
- Render
- Other (specify)

*Skip if vercel.json or render.yaml exists.*

### 8. Repository setup? (skip if git remote already configured)
- Create new repository
- Connect to existing repository
- Skip (local only for now)

If creating new:
- What should the repo be named?
- Public or private?

### 9. Which AI CLI tools do you use? (auto-detect)
- Claude Code only (default)
- Claude Code + Kimi CLI
- Claude Code + Codex CLI
- All three (Claude + Kimi + Codex)

*Auto-detect using `$BOOTSTRAP_DIR/scripts/detect-agents.sh`. Pre-select based on what's installed. If only Claude is detected, skip this question and default to Claude-only.*

### 10. Enable container isolation for parallel agents? (auto-detect)
- **Yes** (default if Docker/OrbStack detected) — Each feature agent runs in its own container
- **No** — Agents share the workspace (native Agent tool)

*Auto-detect Docker/OrbStack. If available, default to Yes and skip this question. Only ask if Docker IS available and you want to confirm, or if Docker is NOT available (inform user and default to No).*

```bash
if echo "$DETECTED_AGENTS" | grep -qE "docker|orbstack"; then
    echo "Docker detected — container isolation enabled by default"
    USE_POLYPHONY="true"
else
    echo "Docker not found — agents will share the workspace"
    USE_POLYPHONY="false"
fi
```

---

## Phase 4: Execute Setup

### Step 1: Create/update directory structure
```bash
mkdir -p .claude/skills
mkdir -p docs
mkdir -p _project_specs/features
mkdir -p _project_specs/todos
mkdir -p _project_specs/prompts
mkdir -p _project_specs/session/archive
mkdir -p scripts

# Cross-tool directories (if selected in question 9)
if [ "$USE_KIMI" = "true" ]; then
    mkdir -p .kimi/skills
fi
if [ "$USE_CODEX" = "true" ]; then
    mkdir -p .codex/skills
fi
# Generic .agents/ always created for cross-tool compat
mkdir -p .agents/skills
```

### Step 2: Update skill files from ~/.claude/skills/

**Skills use folder structure:** Each skill is a folder containing `SKILL.md`.

```bash
# Copy skill folders (not flat .md files)
cp -r ~/.claude/skills/base/ .claude/skills/
cp -r ~/.claude/skills/security/ .claude/skills/
cp -r ~/.claude/skills/project-tooling/ .claude/skills/
cp -r ~/.claude/skills/session-management/ .claude/skills/
cp -r ~/.claude/skills/code-graph/ .claude/skills/
cp -r ~/.claude/skills/cross-agent-delegation/ .claude/skills/
```

**Always copy (overwrite with latest):**
- `base/` → `.claude/skills/base/`
- `security/` → `.claude/skills/security/`
- `project-tooling/` → `.claude/skills/project-tooling/`
- `session-management/` → `.claude/skills/session-management/`
- `code-graph/` → `.claude/skills/code-graph/`
- `cross-agent-delegation/` → `.claude/skills/cross-agent-delegation/`

**If deep analysis or security audit selected (question 4b):**
- `cpg-analysis/` → `.claude/skills/cpg-analysis/`

```bash
# Copy CPG analysis skill if Tier 2 or 3 selected
if [ "$GRAPH_TIER" != "standard" ]; then
    cp -r ~/.claude/skills/cpg-analysis/ .claude/skills/
fi
```

**For existing codebases (detected in Phase 1b):**
- `existing-repo/` → `.claude/skills/existing-repo/` - Structure preservation, guardrails setup

**Based on language:**
- Python → copy `python/`
- TypeScript/JavaScript → copy `typescript/`

**Based on project type:**
- React Native → copy `typescript/` AND `react-native/`
- React Web → copy `typescript/` AND `react-web/`
- Node Backend → copy `typescript/` AND `nodejs-backend/`
- Full Stack (Node + React) → copy `typescript/`, `nodejs-backend/`, AND `react-web/`

**For Android/Flutter projects (auto-detect from project structure):**

| Detection | Skills to Copy |
|-----------|---------------|
| `pubspec.yaml` exists | `flutter/` |
| `android/*.java` exists | `android-java/` |
| `android/*.kt` exists | `android-kotlin/` |
| Flutter + Java files | `flutter/` + `android-java/` |
| Flutter + Kotlin files | `flutter/` + `android-kotlin/` |
| Flutter + Both | `flutter/` + `android-java/` + `android-kotlin/` |

```bash
# Detect and copy Android/Flutter skills
if [ -f "pubspec.yaml" ]; then
  cp -r ~/.claude/skills/flutter/ .claude/skills/
fi

if find android -name "*.java" -type f 2>/dev/null | head -1 | grep -q .; then
  cp -r ~/.claude/skills/android-java/ .claude/skills/
fi

if find android -name "*.kt" -type f 2>/dev/null | head -1 | grep -q .; then
  cp -r ~/.claude/skills/android-kotlin/ .claude/skills/
fi
```

**If AI-first:**
- Copy `llm-patterns/`

**If container isolation enabled (question 10):**
- Copy `polyphony/`

```bash
if [ "$USE_POLYPHONY" = "true" ]; then
    cp -r ~/.claude/skills/polyphony/ .claude/skills/
fi
```

**Note:** Skills are always overwritten with the latest version from ~/.claude/skills/. This ensures updates propagate when user updates their global skills.

### Step 2b: Cross-tool skill sync (if Kimi or Codex selected)

After copying skills to `.claude/skills/`, sync to other tool directories:

```bash
# Sync skills to all selected tools
for skill_dir in .claude/skills/*/; do
    [ -d "$skill_dir" ] || continue

    # Kimi CLI
    if [ "$USE_KIMI" = "true" ]; then
        cp -r "$skill_dir" .kimi/skills/
    fi

    # Codex CLI
    if [ "$USE_CODEX" = "true" ]; then
        cp -r "$skill_dir" .codex/skills/
    fi

    # Generic .agents/ (always)
    cp -r "$skill_dir" .agents/skills/
done

echo "Skills synced to cross-tool directories"
```

### Step 2c: Generate AGENTS.md (if Codex selected)

If Codex was selected in question 9, generate `AGENTS.md` alongside `CLAUDE.md`:

**If AGENTS.md exists:** Preserve customizations, update skill references to `.agents/skills/` paths.

**If new:** Generate from `CLAUDE.md` content, replacing `.claude/skills/` references with `.agents/skills/` paths. The structure mirrors CLAUDE.md but uses the generic skill path that Codex reads.

```bash
if [ "$USE_CODEX" = "true" ] && [ ! -f "AGENTS.md" ]; then
    if [ -f "CLAUDE.md" ]; then
        # Generate from existing CLAUDE.md
        sed 's|\.claude/skills/|.agents/skills/|g' CLAUDE.md > AGENTS.md
        echo "Generated AGENTS.md from CLAUDE.md"
    else
        # Copy template
        cp "$BOOTSTRAP_DIR/templates/AGENTS.md" ./AGENTS.md
        echo "Created AGENTS.md from template"
    fi
fi
```

### Step 2d: Generate config.toml hooks (if Kimi or Codex selected)

```bash
BOOTSTRAP_DIR=$(cat ~/.claude/.bootstrap-dir 2>/dev/null)

if [ "$USE_KIMI" = "true" ]; then
    cp "$BOOTSTRAP_DIR/templates/config.toml" .kimi/config.toml
    echo "Created .kimi/config.toml with hooks"
fi

if [ "$USE_CODEX" = "true" ]; then
    cp "$BOOTSTRAP_DIR/templates/config.toml" .codex/config.toml
    echo "Created .codex/config.toml with hooks"
fi
```

### Step 3: Create/update .gitignore (if missing or incomplete)

Ensure these security-critical entries exist:
```gitignore
# Environment files - NEVER commit
.env
.env.*
!.env.example

# Secrets
*.pem
*.key
*.p12
credentials.json
secrets.json
service-account*.json

# Dependencies
node_modules/
__pycache__/
*.pyc
.venv/
venv/

# Build outputs
dist/
build/

# Code graph data (auto-generated)
.code-graph/

# Cross-tool agent dirs (derived from .claude/skills/, regenerated by /sync-agents)
.kimi/
.codex/
.agents/

# IDE
.idea/
.vscode/settings.json
.DS_Store
```

### Step 4: Create .env.example (if missing)

Based on project type:
```bash
# .env.example - Copy to .env and fill in values
# Server-side only (NEVER prefix with VITE_ or NEXT_PUBLIC_)
DATABASE_URL=
ANTHROPIC_API_KEY=

# Client-side safe (public, non-sensitive)
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
```

### Step 4b: Configure Code Graph MCP Servers

**This step runs for ALL projects** (Tier 1 is always-on).

#### Create/merge .mcp.json

```bash
# Check if .mcp.json exists
if [ -f ".mcp.json" ]; then
    echo "Existing .mcp.json found - will merge code graph config"
else
    echo "Creating .mcp.json for code graph MCP servers"
fi
```

**Always add (Tier 1 — codebase-memory-mcp):**
```json
{
  "mcpServers": {
    "codebase-memory": {
      "command": "codebase-memory-mcp",
      "args": []
    }
  }
}
```

**If Tier 2 selected (deep analysis / full), also add:**
```json
{
  "mcpServers": {
    "codebadger": {
      "url": "http://localhost:4242/mcp",
      "type": "http"
    }
  }
}
```

**If Tier 3 selected (security audit / full), also add:**
```json
{
  "mcpServers": {
    "codeql": {
      "command": "codeql-mcp",
      "args": ["--database", ".code-graph/codeql-db"]
    }
  }
}
```

**Merge strategy:** If `.mcp.json` already exists, read it, merge new `mcpServers` entries without overwriting existing ones, write back.

#### Add .code-graph/ to .gitignore

Ensure this entry exists in `.gitignore`:
```gitignore
# Code graph data (auto-generated, machine-specific)
.code-graph/
```

#### Auto-install codebase-memory-mcp (if not found)

```bash
if ! command -v codebase-memory-mcp &> /dev/null; then
    echo ""
    echo "Installing codebase-memory-mcp (Tier 1 code graph)..."

    # Run the graph tools installer (Tier 1 only by default)
    if [ -f "$HOME/.claude/install-graph-tools.sh" ]; then
        bash "$HOME/.claude/install-graph-tools.sh"
    else
        # Fallback: inline install
        INSTALL_DIR="$HOME/.local/bin"
        mkdir -p "$INSTALL_DIR"
        OS=$(uname -s | tr '[:upper:]' '[:lower:]')
        ARCH=$(uname -m)
        case "$ARCH" in
            aarch64|arm64) ARCH="arm64" ;;
            x86_64|amd64) ARCH="amd64" ;;
        esac
        DOWNLOAD_URL="https://github.com/DeusData/codebase-memory-mcp/releases/latest/download/codebase-memory-mcp-${OS}-${ARCH}.tar.gz"
        TEMP_DIR=$(mktemp -d)
        if curl -fsSL "$DOWNLOAD_URL" -o "$TEMP_DIR/codebase-memory-mcp.tar.gz"; then
            tar xzf "$TEMP_DIR/codebase-memory-mcp.tar.gz" -C "$TEMP_DIR"
            mv "$TEMP_DIR/codebase-memory-mcp" "$INSTALL_DIR/codebase-memory-mcp"
            chmod +x "$INSTALL_DIR/codebase-memory-mcp"
            echo "✓ Installed codebase-memory-mcp to $INSTALL_DIR"
            # Auto-configure for Claude Code
            "$INSTALL_DIR/codebase-memory-mcp" install 2>/dev/null || true
        else
            echo "⚠ Failed to download codebase-memory-mcp"
            echo "  Manual install: ~/.claude/install-graph-tools.sh"
        fi
        rm -rf "$TEMP_DIR"
    fi
else
    echo "✓ codebase-memory-mcp already installed"
fi
```

#### Auto-install Tier 2/3 tools (if selected)

```bash
# Tier 2: Joern CPG (if deep analysis or full selected)
if [ "$GRAPH_TIER" = "deep" ] || [ "$GRAPH_TIER" = "full" ]; then
    if [ -f "$HOME/.claude/install-graph-tools.sh" ]; then
        echo ""
        echo "Installing Joern CPG (Tier 2)..."
        bash "$HOME/.claude/install-graph-tools.sh" --joern
    fi
fi

# Tier 3: CodeQL (if security audit or full selected)
if [ "$GRAPH_TIER" = "security" ] || [ "$GRAPH_TIER" = "full" ]; then
    if [ -f "$HOME/.claude/install-graph-tools.sh" ]; then
        echo ""
        echo "Installing CodeQL (Tier 3)..."
        bash "$HOME/.claude/install-graph-tools.sh" --codeql
    fi
fi
```

#### Enable auto-indexing and build initial graph

```bash
if command -v codebase-memory-mcp &> /dev/null; then
    # Enable auto-index so graph stays fresh across sessions
    codebase-memory-mcp config set auto_index true 2>/dev/null || true

    # Build initial graph index for this project
    echo ""
    echo "Building code graph index (first time may take a moment)..."
    codebase-memory-mcp index --project-dir . 2>/dev/null || {
        echo "⚠ Initial index failed - graph will be built on first MCP query"
    }
    echo "✓ Code graph indexed"
fi
```

#### Install post-commit graph update hook

```bash
if [ -d ".git" ]; then
    # Append to existing post-commit hook (don't overwrite)
    if [ -f ".git/hooks/post-commit" ]; then
        if ! grep -q "code-graph" ".git/hooks/post-commit"; then
            echo "" >> .git/hooks/post-commit
            echo "# Code graph incremental update" >> .git/hooks/post-commit
            cat ~/.claude/hooks/post-commit-graph >> .git/hooks/post-commit
        fi
    else
        cp ~/.claude/hooks/post-commit-graph .git/hooks/post-commit
        chmod +x .git/hooks/post-commit
    fi
    echo "✓ Post-commit graph update hook installed"
fi
```

### Step 5: Create/update verification script
Create or overwrite `scripts/verify-tooling.sh`:

```bash
#!/bin/bash
set -e

echo "Verifying project tooling..."

# GitHub CLI
if command -v gh &> /dev/null; then
  if gh auth status &> /dev/null; then
    echo "✓ GitHub CLI authenticated"
  else
    echo "✗ GitHub CLI not authenticated. Run: gh auth login"
    exit 1
  fi
else
  echo "⚠ GitHub CLI not installed. Run: brew install gh"
fi

# Vercel CLI
if command -v vercel &> /dev/null; then
  if vercel whoami &> /dev/null; then
    echo "✓ Vercel CLI authenticated"
  else
    echo "✗ Vercel CLI not authenticated. Run: vercel login"
    exit 1
  fi
else
  echo "⚠ Vercel CLI not installed. Run: npm i -g vercel"
fi

# Supabase CLI
if command -v supabase &> /dev/null; then
  if supabase projects list &> /dev/null 2>&1; then
    echo "✓ Supabase CLI authenticated"
  else
    echo "✗ Supabase CLI not authenticated. Run: supabase login"
    exit 1
  fi
else
  echo "⚠ Supabase CLI not installed. Run: brew install supabase/tap/supabase"
fi

echo ""
echo "Tooling verification complete!"
```

```bash
chmod +x scripts/verify-tooling.sh
```

### Step 6: Create security check script

Create `scripts/security-check.sh`:
```bash
Download .txt
gitextract_idptty0p/

├── .github/
│   └── workflows/
│       ├── skill-lint.yml
│       └── skill-review.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── _project_specs/
│   ├── 00-autonomous-engineering-roadmap.md
│   ├── 01-runtime-observability.md
│   ├── 02-rollback-and-recovery.md
│   ├── 03-verifiable-contracts.md
│   ├── 04-multi-agent-coordination.md
│   ├── 05-confidence-calibration.md
│   ├── 06-cost-budget-awareness.md
│   ├── 07-human-escalation-protocol.md
│   ├── 08-auto-code-index.md
│   └── 09-multimodal-ingestion.md
├── commands/
│   ├── analyze-repo.md
│   ├── analyze-workspace.md
│   ├── check-contributors.md
│   ├── icpg-bootstrap.md
│   ├── icpg-drift.md
│   ├── icpg-impact.md
│   ├── icpg-why.md
│   ├── initialize-project.md
│   ├── maggy-init.md
│   ├── maggy.md
│   ├── mnemos-checkpoint.md
│   ├── mnemos-status.md
│   ├── polyphony-init.md
│   ├── polyphony-spawn.md
│   ├── polyphony-status.md
│   ├── spawn-team.md
│   ├── sync-agents.md
│   ├── sync-contracts.md
│   └── update-code-index.md
├── docs/
│   ├── architecture-v5.md
│   ├── benchmark-results.md
│   ├── mnemos-implementation.md
│   └── polyphony-spec.md
├── evals/
│   ├── README.md
│   ├── agent-teams/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── base/
│   │   ├── scenario-1/
│   │   │   ├── criteria.json
│   │   │   └── task.md
│   │   └── scenario-2/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── code-review/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── commit-hygiene/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── credentials/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── database-schema/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── existing-repo/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── llm-patterns/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── project-tooling/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── python/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── react-web/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── run-evals.sh
│   ├── security/
│   │   ├── scenario-1/
│   │   │   ├── criteria.json
│   │   │   └── task.md
│   │   └── scenario-2/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── session-management/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   ├── supabase/
│   │   └── scenario-1/
│   │       ├── criteria.json
│   │       └── task.md
│   └── typescript/
│       └── scenario-1/
│           ├── criteria.json
│           └── task.md
├── hooks/
│   ├── post-commit-graph
│   ├── pre-push
│   └── workspace/
│       ├── check-contract-freshness.sh
│       ├── check-graph-freshness.sh
│       ├── post-commit-contracts.sh
│       └── pre-push-contracts.sh
├── install.sh
├── maggy/
│   ├── .gitignore
│   ├── PLAN.md
│   ├── README.md
│   ├── config.example.yaml
│   ├── docs/
│   │   ├── benchmark-results.md
│   │   └── maggy-rfc.md
│   ├── install.sh
│   ├── maggy/
│   │   ├── __init__.py
│   │   ├── adapters/
│   │   │   ├── __init__.py
│   │   │   ├── cli_discovery.py
│   │   │   └── pi.py
│   │   ├── api/
│   │   │   ├── __init__.py
│   │   │   ├── auth.py
│   │   │   ├── routes.py
│   │   │   ├── routes_budget.py
│   │   │   ├── routes_chat.py
│   │   │   ├── routes_cikg.py
│   │   │   ├── routes_deploy.py
│   │   │   ├── routes_engram.py
│   │   │   ├── routes_escalation.py
│   │   │   ├── routes_events.py
│   │   │   ├── routes_forge.py
│   │   │   ├── routes_heartbeat.py
│   │   │   ├── routes_history.py
│   │   │   ├── routes_improve.py
│   │   │   ├── routes_lexon.py
│   │   │   ├── routes_mesh.py
│   │   │   ├── routes_mesh_admin.py
│   │   │   ├── routes_monitor.py
│   │   │   ├── routes_observability.py
│   │   │   ├── routes_planning.py
│   │   │   ├── routes_process.py
│   │   │   ├── routes_projects.py
│   │   │   ├── routes_routing.py
│   │   │   └── routes_setup.py
│   │   ├── budget.py
│   │   ├── calibration/
│   │   │   ├── __init__.py
│   │   │   └── tracker.py
│   │   ├── checkpoint.py
│   │   ├── cikg/
│   │   │   ├── __init__.py
│   │   │   ├── graph.py
│   │   │   ├── models.py
│   │   │   ├── queries.py
│   │   │   └── storage.py
│   │   ├── cli.py
│   │   ├── cli_chat.py
│   │   ├── cli_client.py
│   │   ├── cli_output.py
│   │   ├── cli_repl_cmds.py
│   │   ├── cli_sessions.py
│   │   ├── cli_welcome.py
│   │   ├── config.py
│   │   ├── contracts/
│   │   │   ├── __init__.py
│   │   │   └── generator.py
│   │   ├── coordination/
│   │   │   ├── __init__.py
│   │   │   └── lock_manager.py
│   │   ├── deploy.py
│   │   ├── discovery.py
│   │   ├── engram/
│   │   │   ├── __init__.py
│   │   │   ├── diagnostics.py
│   │   │   ├── record.py
│   │   │   ├── retrieval.py
│   │   │   ├── seed.py
│   │   │   └── store.py
│   │   ├── escalation/
│   │   │   ├── __init__.py
│   │   │   └── protocol.py
│   │   ├── event_spine/
│   │   │   ├── __init__.py
│   │   │   ├── emitter.py
│   │   │   ├── events.py
│   │   │   ├── header.py
│   │   │   └── store.py
│   │   ├── fatigue.py
│   │   ├── forge/
│   │   │   ├── __init__.py
│   │   │   ├── connector.py
│   │   │   ├── detector.py
│   │   │   └── registry.py
│   │   ├── heartbeat/
│   │   │   ├── __init__.py
│   │   │   ├── jobs.py
│   │   │   └── scheduler.py
│   │   ├── history/
│   │   │   ├── __init__.py
│   │   │   ├── analyzer.py
│   │   │   ├── models.py
│   │   │   ├── parsers/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── claude.py
│   │   │   │   ├── codex.py
│   │   │   │   └── kimi.py
│   │   │   ├── service.py
│   │   │   └── store.py
│   │   ├── improve/
│   │   │   ├── __init__.py
│   │   │   ├── analyzer.py
│   │   │   ├── models.py
│   │   │   ├── service.py
│   │   │   └── signals.py
│   │   ├── lexon/
│   │   │   ├── __init__.py
│   │   │   ├── disambiguate.py
│   │   │   ├── personalization.py
│   │   │   ├── record.py
│   │   │   ├── router.py
│   │   │   └── terminology.py
│   │   ├── main.py
│   │   ├── mesh/
│   │   │   ├── __init__.py
│   │   │   ├── discovery.py
│   │   │   ├── git_discovery.py
│   │   │   ├── manager.py
│   │   │   ├── memory.py
│   │   │   ├── network.py
│   │   │   ├── org_scanner.py
│   │   │   ├── protocol.py
│   │   │   ├── provenance.py
│   │   │   ├── publisher.py
│   │   │   ├── quarantine.py
│   │   │   ├── store.py
│   │   │   ├── sync.py
│   │   │   ├── transport.py
│   │   │   ├── ws_client.py
│   │   │   └── ws_server.py
│   │   ├── mnemos/
│   │   │   ├── __init__.py
│   │   │   ├── fatigue.py
│   │   │   └── signals.py
│   │   ├── models/
│   │   │   ├── __init__.py
│   │   │   └── plan.py
│   │   ├── observability/
│   │   │   ├── __init__.py
│   │   │   └── collector.py
│   │   ├── planning.py
│   │   ├── process/
│   │   │   ├── __init__.py
│   │   │   ├── discovery.py
│   │   │   ├── github_prs.py
│   │   │   ├── model_router.py
│   │   │   ├── models.py
│   │   │   ├── patterns.py
│   │   │   ├── report.py
│   │   │   ├── service.py
│   │   │   ├── signals.py
│   │   │   └── store.py
│   │   ├── providers/
│   │   │   ├── __init__.py
│   │   │   ├── asana.py
│   │   │   ├── base.py
│   │   │   ├── github_issues.py
│   │   │   └── monday.py
│   │   ├── recovery/
│   │   │   ├── __init__.py
│   │   │   └── rollback.py
│   │   ├── registry.py
│   │   ├── routing.py
│   │   ├── routing_rules.py
│   │   ├── routing_rules_defaults.py
│   │   ├── routing_rules_io.py
│   │   ├── scores.py
│   │   ├── services/
│   │   │   ├── __init__.py
│   │   │   ├── account_guide.py
│   │   │   ├── activity.py
│   │   │   ├── ai_client.py
│   │   │   ├── cascade.py
│   │   │   ├── chat.py
│   │   │   ├── chat_context.py
│   │   │   ├── chat_router.py
│   │   │   ├── chat_stream.py
│   │   │   ├── checkpoint.py
│   │   │   ├── competitor.py
│   │   │   ├── context_compactor.py
│   │   │   ├── convention_inferrer.py
│   │   │   ├── convention_scanner.py
│   │   │   ├── executor.py
│   │   │   ├── executor_helpers.py
│   │   │   ├── executor_prompts.py
│   │   │   ├── executor_types.py
│   │   │   ├── inbox.py
│   │   │   ├── monitor.py
│   │   │   ├── output_reviewer.py
│   │   │   ├── planner.py
│   │   │   ├── session_detect.py
│   │   │   ├── stakes.py
│   │   │   ├── tdd_verifier.py
│   │   │   └── vision.py
│   │   └── static/
│   │       ├── app.js
│   │       └── index.html
│   ├── pyproject.toml
│   └── tests/
│       ├── conftest.py
│       ├── integration/
│       │   ├── __init__.py
│       │   ├── test_full_task_flow.py
│       │   ├── test_model_fallback.py
│       │   └── test_process_loop.py
│       ├── test_account_guide.py
│       ├── test_activity.py
│       ├── test_api_endpoints.py
│       ├── test_benchmark_scenario.py
│       ├── test_bootstrap.py
│       ├── test_budget.py
│       ├── test_calibration.py
│       ├── test_cascade.py
│       ├── test_chat.py
│       ├── test_chat_context.py
│       ├── test_chat_routed.py
│       ├── test_chat_router.py
│       ├── test_chat_stream.py
│       ├── test_checkpoint.py
│       ├── test_checkpoint_mgr.py
│       ├── test_cikg.py
│       ├── test_cli.py
│       ├── test_cli_chat.py
│       ├── test_cli_discovery.py
│       ├── test_cli_sessions.py
│       ├── test_cli_welcome.py
│       ├── test_context_compactor.py
│       ├── test_contracts.py
│       ├── test_convention_inferrer.py
│       ├── test_convention_scanner.py
│       ├── test_coordination.py
│       ├── test_deploy.py
│       ├── test_discovery.py
│       ├── test_dual_planner.py
│       ├── test_engram.py
│       ├── test_escalation.py
│       ├── test_event_spine.py
│       ├── test_executor_routing.py
│       ├── test_fatigue.py
│       ├── test_forge.py
│       ├── test_heartbeat.py
│       ├── test_history.py
│       ├── test_history_parsers.py
│       ├── test_improve.py
│       ├── test_lexon.py
│       ├── test_mesh.py
│       ├── test_mesh_network.py
│       ├── test_mesh_store.py
│       ├── test_mesh_ws.py
│       ├── test_mnemos_fatigue.py
│       ├── test_monday_provider.py
│       ├── test_monitor.py
│       ├── test_multimodel_integration.py
│       ├── test_observability.py
│       ├── test_output_reviewer.py
│       ├── test_pi_adapter.py
│       ├── test_planning.py
│       ├── test_registry.py
│       ├── test_repl_cmds.py
│       ├── test_rollback.py
│       ├── test_routes_escalation.py
│       ├── test_routes_observability.py
│       ├── test_routes_projects.py
│       ├── test_routing_config.py
│       ├── test_routing_rules.py
│       ├── test_routing_service.py
│       ├── test_scores.py
│       ├── test_setup_routes.py
│       ├── test_stakes.py
│       ├── test_tdd_verifier.py
│       ├── test_vision.py
│       └── test_zero_config.py
├── rules/
│   ├── nodejs-backend.md
│   ├── python.md
│   ├── quality-gates.md
│   ├── react.md
│   ├── security.md
│   ├── tdd-workflow.md
│   └── typescript.md
├── scripts/
│   ├── convert-hooks-to-toml.sh
│   ├── convert-skills-structure.sh
│   ├── detect-agents.sh
│   ├── icpg/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── bootstrap.py
│   │   ├── contracts.py
│   │   ├── drift.py
│   │   ├── models.py
│   │   ├── pyproject.toml
│   │   ├── store.py
│   │   ├── symbols.py
│   │   └── vectors.py
│   ├── install-graph-tools.sh
│   ├── install-hooks.sh
│   ├── install-skills.sh
│   ├── mnemos/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── checkpoint.py
│   │   ├── consolidation.py
│   │   ├── fatigue.py
│   │   ├── models.py
│   │   ├── pyproject.toml
│   │   ├── signals.py
│   │   └── store.py
│   ├── polyphony/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── adapters/
│   │   │   ├── __init__.py
│   │   │   ├── claude.py
│   │   │   ├── codex.py
│   │   │   └── kimi.py
│   │   ├── config.py
│   │   ├── events.py
│   │   ├── identity.py
│   │   ├── models.py
│   │   ├── orchestrator.py
│   │   ├── pyproject.toml
│   │   ├── router.py
│   │   ├── runtime.py
│   │   ├── scoring.py
│   │   ├── sources/
│   │   │   ├── __init__.py
│   │   │   ├── github.py
│   │   │   └── local.py
│   │   ├── state_machine.py
│   │   ├── store.py
│   │   └── workspace.py
│   └── skill_lint/
│       ├── __init__.py
│       ├── __main__.py
│       ├── content.py
│       ├── frontmatter.py
│       ├── pyproject.toml
│       ├── references.py
│       ├── report.py
│       └── spec.py
├── skills/
│   ├── aeo-optimization/
│   │   └── SKILL.md
│   ├── agent-teams/
│   │   ├── SKILL.md
│   │   └── agents/
│   │       ├── code-review.md
│   │       ├── feature.md
│   │       ├── merger.md
│   │       ├── quality.md
│   │       ├── security.md
│   │       └── team-lead.md
│   ├── agentic-development/
│   │   └── SKILL.md
│   ├── ai-models/
│   │   └── SKILL.md
│   ├── android-java/
│   │   └── SKILL.md
│   ├── android-kotlin/
│   │   └── SKILL.md
│   ├── aws-aurora/
│   │   └── SKILL.md
│   ├── aws-dynamodb/
│   │   └── SKILL.md
│   ├── azure-cosmosdb/
│   │   └── SKILL.md
│   ├── base/
│   │   └── SKILL.md
│   ├── cloudflare-d1/
│   │   └── SKILL.md
│   ├── code-deduplication/
│   │   └── SKILL.md
│   ├── code-graph/
│   │   └── SKILL.md
│   ├── code-review/
│   │   └── SKILL.md
│   ├── codex-review/
│   │   └── SKILL.md
│   ├── commit-hygiene/
│   │   └── SKILL.md
│   ├── cpg-analysis/
│   │   └── SKILL.md
│   ├── credentials/
│   │   └── SKILL.md
│   ├── cross-agent-delegation/
│   │   └── SKILL.md
│   ├── database-schema/
│   │   └── SKILL.md
│   ├── existing-repo/
│   │   └── SKILL.md
│   ├── firebase/
│   │   └── SKILL.md
│   ├── flutter/
│   │   └── SKILL.md
│   ├── gemini-review/
│   │   └── SKILL.md
│   ├── icpg/
│   │   └── SKILL.md
│   ├── iterative-development/
│   │   └── SKILL.md
│   ├── klaviyo/
│   │   └── SKILL.md
│   ├── llm-patterns/
│   │   └── SKILL.md
│   ├── maggy/
│   │   └── SKILL.md
│   ├── medusa/
│   │   └── SKILL.md
│   ├── mnemos/
│   │   └── SKILL.md
│   ├── ms-teams-apps/
│   │   └── SKILL.md
│   ├── nodejs-backend/
│   │   └── SKILL.md
│   ├── playwright-testing/
│   │   └── SKILL.md
│   ├── polyphony/
│   │   └── SKILL.md
│   ├── posthog-analytics/
│   │   └── SKILL.md
│   ├── project-tooling/
│   │   └── SKILL.md
│   ├── pwa-development/
│   │   └── SKILL.md
│   ├── python/
│   │   └── SKILL.md
│   ├── react-native/
│   │   └── SKILL.md
│   ├── react-web/
│   │   └── SKILL.md
│   ├── reddit-ads/
│   │   └── SKILL.md
│   ├── reddit-api/
│   │   └── SKILL.md
│   ├── security/
│   │   └── SKILL.md
│   ├── session-management/
│   │   └── SKILL.md
│   ├── shopify-apps/
│   │   └── SKILL.md
│   ├── site-architecture/
│   │   └── SKILL.md
│   ├── supabase/
│   │   └── SKILL.md
│   ├── supabase-nextjs/
│   │   └── SKILL.md
│   ├── supabase-node/
│   │   └── SKILL.md
│   ├── supabase-python/
│   │   └── SKILL.md
│   ├── team-coordination/
│   │   └── SKILL.md
│   ├── ticket-craft/
│   │   └── SKILL.md
│   ├── typescript/
│   │   └── SKILL.md
│   ├── ui-mobile/
│   │   └── SKILL.md
│   ├── ui-testing/
│   │   └── SKILL.md
│   ├── ui-web/
│   │   └── SKILL.md
│   ├── user-journeys/
│   │   └── SKILL.md
│   ├── web-content/
│   │   └── SKILL.md
│   ├── web-payments/
│   │   └── SKILL.md
│   ├── woocommerce/
│   │   └── SKILL.md
│   └── workspace/
│       └── SKILL.md
├── templates/
│   ├── AGENTS.md
│   ├── CLAUDE.local.md
│   ├── CLAUDE.md
│   ├── Dockerfile.polyphony
│   ├── codex-auto-review.sh
│   ├── config.toml
│   ├── icpg-pre-edit.sh
│   ├── icpg-stop-record.sh
│   ├── mnemos-post-compact-inject.sh
│   ├── mnemos-post-tool.sh
│   ├── mnemos-pre-compact.sh
│   ├── mnemos-pre-edit.sh
│   ├── mnemos-session-start.sh
│   ├── mnemos-statusline.sh
│   ├── mnemos-stop-checkpoint.sh
│   ├── polyphony-agents.yaml
│   ├── polyphony-config.yaml
│   ├── polyphony-identities.yaml
│   ├── polyphony-routing.yaml
│   ├── pre-compact.sh
│   ├── settings.json
│   └── tdd-loop-check.sh
└── tests/
    ├── test_cross_agent.py
    ├── test_cross_tool.py
    ├── test_polyphony_adapters.py
    ├── test_polyphony_config.py
    ├── test_polyphony_events.py
    ├── test_polyphony_identity.py
    ├── test_polyphony_models.py
    ├── test_polyphony_orchestrator.py
    ├── test_polyphony_router.py
    ├── test_polyphony_runtime.py
    ├── test_polyphony_scoring.py
    ├── test_polyphony_sources.py
    ├── test_polyphony_state.py
    ├── test_polyphony_store.py
    ├── test_polyphony_workspace.py
    ├── test_session_detect.py
    ├── test_skill_lint.py
    └── validate-structure.sh
Download .txt
Showing preview only (245K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2970 symbols across 274 files)

FILE: maggy/maggy/adapters/cli_discovery.py
  class CliProfile (line 21) | class CliProfile:
    method build_command (line 39) | def build_command(
  class DiscoveryResult (line 70) | class DiscoveryResult:
  function discover_all (line 80) | def discover_all() -> DiscoveryResult:
  function discover_cli (line 91) | def discover_cli(name: str) -> CliProfile:
  function _extract_flags (line 110) | def _extract_flags(profile: CliProfile, text: str) -> None:
  function _refine_from_exec (line 154) | def _refine_from_exec(profile: CliProfile, text: str) -> None:
  function _refine_from_run (line 162) | def _refine_from_run(profile: CliProfile, text: str) -> None:
  function _post_process (line 168) | def _post_process(profile: CliProfile) -> None:
  function _detect_ollama_model (line 193) | def _detect_ollama_model(profile: CliProfile) -> str:
  function _has (line 223) | def _has(text: str, pattern: str) -> bool:
  function _get_version (line 228) | def _get_version(binary: str) -> str:
  function _get_help (line 245) | def _get_help(binary: str, subcommand: str) -> str:
  function _clean_env (line 262) | def _clean_env() -> dict[str, str]:

FILE: maggy/maggy/adapters/pi.py
  function _extract_usage (line 28) | def _extract_usage(raw: str) -> tuple[float, int, int, str]:
  class ModelEntry (line 44) | class ModelEntry:
  class RunResult (line 69) | class RunResult:
  class PiAdapter (line 81) | class PiAdapter:
    method __init__ (line 82) | def __init__(
    method get_model (line 100) | def get_model(self, name: str) -> ModelEntry | None:
    method list_models (line 103) | def list_models(self) -> list[ModelEntry]:
    method fallback_chain (line 106) | def fallback_chain(self, start: str) -> list[str]:
    method send_prompt (line 113) | async def send_prompt(
    method send_with_fallback (line 135) | async def send_with_fallback(
    method send_rpc (line 152) | def send_rpc(self, command: dict[str, object]) -> dict[str, object]:
    method switch_model (line 163) | def switch_model(self, provider: str, model: str) -> bool:
    method stream_events (line 167) | async def stream_events(self) -> AsyncIterator[dict[str, object]]:
    method _build_command (line 181) | def _build_command(
    method _detect_quota (line 189) | def _detect_quota(self, text: str) -> bool:
    method _detect_pi (line 192) | def _detect_pi(self) -> bool:
    method _spawn_prompt (line 195) | async def _spawn_prompt(
    method _log_discovery (line 212) | def _log_discovery(self) -> None:
    method discovered_profiles (line 218) | def discovered_profiles(self) -> dict[str, CliProfile]:
    method _prompt_result (line 221) | def _prompt_result(self, model_name: str, code: int, stdout: bytes) ->...
    method _ensure_rpc_process (line 232) | def _ensure_rpc_process(self) -> subprocess.Popen[str]:
    method _require_stream (line 243) | def _require_stream(self, stream: object, name: str):

FILE: maggy/maggy/api/auth.py
  function check_auth (line 8) | def check_auth(
  function require_configured (line 23) | def require_configured(request: Request) -> None:
  function require_provider (line 32) | def require_provider(request: Request) -> None:

FILE: maggy/maggy/api/routes.py
  function _auth (line 16) | def _auth(request: Request, x_api_key: str | None) -> None:
  function _require_configured (line 26) | def _require_configured(request: Request) -> None:
  function health (line 40) | async def health(request: Request) -> dict:
  function get_activity (line 57) | async def get_activity(request: Request) -> dict:
  function get_discovery (line 63) | async def get_discovery(request: Request) -> dict:
  function get_config (line 77) | async def get_config(request: Request, x_api_key: str | None = Header(No...
  function get_inbox (line 94) | async def get_inbox(request: Request, refresh: bool = Query(False), x_ap...
  function get_followed (line 102) | async def get_followed(request: Request, x_api_key: str | None = Header(...
  function get_task (line 125) | async def get_task(request: Request, task_id: str, x_api_key: str | None...
  class CommentRequest (line 152) | class CommentRequest(BaseModel):
  function post_comment (line 157) | async def post_comment(request: Request, task_id: str, body: CommentRequ...
  class StatusRequest (line 172) | class StatusRequest(BaseModel):
  function update_status (line 177) | async def update_status(request: Request, task_id: str, body: StatusRequ...
  class ExecuteRequest (line 190) | class ExecuteRequest(BaseModel):
  function execute (line 197) | async def execute(request: Request, body: ExecuteRequest, x_api_key: str...
  function list_sessions (line 210) | async def list_sessions(request: Request, x_api_key: str | None = Header...
  function get_session (line 217) | async def get_session(request: Request, session_id: str, x_api_key: str ...
  function list_competitors (line 229) | async def list_competitors(request: Request, x_api_key: str | None = Hea...
  function discover_competitors (line 236) | async def discover_competitors(request: Request, x_api_key: str | None =...
  function trigger_monitoring (line 243) | async def trigger_monitoring(request: Request, x_api_key: str | None = H...
  function get_competitor_news (line 250) | async def get_competitor_news(request: Request, limit: int = Query(100),...
  function get_briefing (line 257) | async def get_briefing(request: Request, refresh: bool = Query(False), x...

FILE: maggy/maggy/api/routes_budget.py
  function get_budget (line 13) | async def get_budget(
  function by_provider (line 26) | async def by_provider(

FILE: maggy/maggy/api/routes_chat.py
  function _require_chat (line 20) | def _require_chat(request: Request):
  class CreateSessionRequest (line 30) | class CreateSessionRequest(BaseModel):
  class SendMessageRequest (line 35) | class SendMessageRequest(BaseModel):
  class RoutedMessageRequest (line 39) | class RoutedMessageRequest(BaseModel):
  function auto_connect (line 47) | async def auto_connect(
  function _enrich_session (line 69) | def _enrich_session(s, history, recent: list[dict]) -> str:
  function _session_summary (line 86) | def _session_summary(s, context: str) -> dict:
  function create_session (line 100) | async def create_session(
  function list_sessions (line 123) | async def list_sessions(
  function get_session (line 143) | async def get_session(
  function send_message (line 166) | async def send_message(
  function send_routed (line 197) | async def send_routed(
  function _record_chat_spend (line 256) | def _record_chat_spend(budget, chunk: dict) -> None:
  function _record_routing_outcome (line 265) | def _record_routing_outcome(routing, decision, *, had_error: bool) -> None:
  function delete_session (line 277) | async def delete_session(

FILE: maggy/maggy/api/routes_cikg.py
  function landscape (line 13) | async def landscape(
  function feature_gaps (line 27) | async def feature_gaps(

FILE: maggy/maggy/api/routes_deploy.py
  class CreateSessionRequest (line 15) | class CreateSessionRequest(BaseModel):
  function list_sessions (line 21) | async def list_sessions(
  function get_session (line 36) | async def get_session(
  function create_session (line 53) | async def create_session(

FILE: maggy/maggy/api/routes_engram.py
  function query_engrams (line 15) | async def query_engrams(
  function diagnostics (line 36) | async def diagnostics(

FILE: maggy/maggy/api/routes_escalation.py
  class _EscalationIn (line 13) | class _EscalationIn(BaseModel):
  class _ResolveIn (line 19) | class _ResolveIn(BaseModel):
  function list_pending (line 24) | async def list_pending(
  function create_escalation (line 43) | async def create_escalation(
  function resolve_escalation (line 60) | async def resolve_escalation(

FILE: maggy/maggy/api/routes_events.py
  function query_events (line 13) | async def query_events(
  function trace_task (line 30) | async def trace_task(
  function count_events (line 44) | async def count_events(

FILE: maggy/maggy/api/routes_forge.py
  class GapReport (line 15) | class GapReport(BaseModel):
  function forge_status (line 20) | async def forge_status(
  function search_tools (line 33) | async def search_tools(
  function list_gaps (line 47) | async def list_gaps(
  function report_gap (line 60) | async def report_gap(

FILE: maggy/maggy/api/routes_heartbeat.py
  function heartbeat_status (line 13) | async def heartbeat_status(
  function trigger_job (line 25) | async def trigger_job(

FILE: maggy/maggy/api/routes_history.py
  function _require_history (line 14) | def _require_history(request: Request):
  function analyze_history (line 25) | async def analyze_history(
  function get_report (line 44) | async def get_report(
  function get_sessions (line 58) | async def get_sessions(
  function list_providers (line 71) | async def list_providers(

FILE: maggy/maggy/api/routes_improve.py
  function get_report (line 15) | async def get_report(
  function run_analysis (line 30) | async def run_analysis(

FILE: maggy/maggy/api/routes_lexon.py
  class LearnRequest (line 15) | class LearnRequest(BaseModel):
  function parse_intent (line 21) | async def parse_intent(
  function learn_mapping (line 36) | async def learn_mapping(

FILE: maggy/maggy/api/routes_mesh.py
  class AddPeerRequest (line 16) | class AddPeerRequest(BaseModel):
  class PromoteRequest (line 24) | class PromoteRequest(BaseModel):
  function mesh_status (line 30) | async def mesh_status(
  function list_networks (line 47) | async def list_networks(
  function list_peers (line 60) | async def list_peers(
  function add_peer (line 93) | async def add_peer(
  function quarantine_list (line 124) | async def quarantine_list(
  function promote (line 152) | async def promote(

FILE: maggy/maggy/api/routes_mesh_admin.py
  function announce (line 14) | async def announce(
  function discover (line 36) | async def discover(
  function setup (line 58) | async def setup(

FILE: maggy/maggy/api/routes_monitor.py
  function monitor_status (line 11) | async def monitor_status(request: Request) -> dict:
  function monitor_start (line 20) | async def monitor_start(request: Request) -> dict:
  function monitor_stop (line 29) | async def monitor_stop(request: Request) -> dict:

FILE: maggy/maggy/api/routes_observability.py
  class _SignalIn (line 15) | class _SignalIn(BaseModel):
  function get_signals (line 22) | async def get_signals(
  function record_signal (line 37) | async def record_signal(

FILE: maggy/maggy/api/routes_planning.py
  class PlanGenerateRequest (line 15) | class PlanGenerateRequest(BaseModel):
  function generate_plan (line 22) | async def generate_plan(

FILE: maggy/maggy/api/routes_process.py
  function _auth (line 15) | def _auth(request: Request, x_api_key: str | None) -> None:
  function _require_process (line 24) | def _require_process(request: Request) -> None:
  class AnalyzeRequest (line 29) | class AnalyzeRequest(BaseModel):
  function analyze (line 34) | async def analyze(
  function get_report (line 61) | async def get_report(
  function get_health (line 76) | async def get_health(

FILE: maggy/maggy/api/routes_projects.py
  class _ProjectIn (line 13) | class _ProjectIn(BaseModel):
  function list_projects (line 21) | async def list_projects(
  function get_project (line 37) | async def get_project(
  function add_project (line 58) | async def add_project(
  function remove_project (line 81) | async def remove_project(

FILE: maggy/maggy/api/routes_routing.py
  function heatmap (line 13) | async def heatmap(
  function decide (line 26) | async def decide(
  function rules (line 50) | async def rules(

FILE: maggy/maggy/api/routes_setup.py
  class ConfigureRequest (line 13) | class ConfigureRequest(BaseModel):
  function _step (line 22) | def _step(label: str, ok: bool, hint: str = "") -> dict:
  function _build_steps (line 31) | def _build_steps(cfg) -> list[dict]:
  function _has_claude_cli (line 50) | def _has_claude_cli() -> bool:
  function _discover_summary (line 56) | def _discover_summary() -> dict:
  function setup_status (line 71) | async def setup_status(request: Request) -> dict:
  function configure (line 89) | async def configure(
  function reload_config (line 107) | async def reload_config(request: Request) -> dict:
  function discover_repos (line 116) | async def discover_repos(request: Request) -> dict:
  function auto_configure (line 133) | async def auto_configure(request: Request) -> dict:
  function cli_models (line 149) | async def cli_models() -> dict:

FILE: maggy/maggy/budget.py
  function _today_utc (line 16) | def _today_utc() -> str:
  function _connect (line 21) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  function _open_conn (line 33) | def _open_conn(path: Path) -> sqlite3.Connection:
  class ProviderBudget (line 58) | class ProviderBudget:
  class TaskSpendTracker (line 66) | class TaskSpendTracker:
    method __init__ (line 69) | def __init__(self, max_spend: float):
    method record (line 74) | def record(self, cost: float) -> None:
    method total (line 77) | def total(self) -> float:
    method is_exceeded (line 80) | def is_exceeded(self) -> bool:
    method record_edit (line 83) | def record_edit(self, file_path: str) -> None:
    method detect_loop (line 87) | def detect_loop(self, threshold: int = 3) -> list[str]:
  class BudgetManager (line 94) | class BudgetManager:
    method __init__ (line 97) | def __init__(self, cfg: MaggyConfig):
    method _init_db (line 109) | def _init_db(self) -> None:
    method record_spend (line 113) | def record_spend(
    method today_spend (line 128) | def today_spend(self, provider: str | None = None) -> float:
    method today_tokens (line 139) | def today_tokens(self, provider: str | None = None) -> dict:
    method budget_status (line 151) | def budget_status(self) -> dict:
    method by_provider (line 167) | def by_provider(self) -> list[dict]:
    method is_exhausted (line 180) | def is_exhausted(
    method is_provider_exhausted (line 187) | def is_provider_exhausted(self, provider: str) -> bool:
    method cheapest_available (line 194) | def cheapest_available(self) -> str | None:

FILE: maggy/maggy/calibration/tracker.py
  function _connect (line 24) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class CalibrationTracker (line 34) | class CalibrationTracker:
    method __init__ (line 35) | def __init__(self, db_path: Path):
    method record (line 39) | def record(
    method accuracy (line 50) | def accuracy(self, model: str) -> float:
    method calibration_error (line 57) | def calibration_error(self, model: str) -> float:
    method _errors (line 63) | def _errors(self, model: str) -> list[float]:
    method _init_db (line 71) | def _init_db(self) -> None:

FILE: maggy/maggy/checkpoint.py
  class CheckpointManager (line 11) | class CheckpointManager:
    method __init__ (line 12) | def __init__(self, base_dir: Path = DEFAULT_DIR):
    method write (line 15) | def write(self, session_id: str, data: dict) -> None:
    method read (line 23) | def read(self, session_id: str) -> dict | None:
    method delete (line 32) | def delete(self, session_id: str) -> bool:
    method list_checkpoints (line 39) | def list_checkpoints(self) -> list[str]:
    method _path (line 45) | def _path(self, session_id: str) -> Path:
  function _sanitize_id (line 53) | def _sanitize_id(session_id: str) -> str:
  function _normalize (line 60) | def _normalize(data: dict) -> dict:

FILE: maggy/maggy/cikg/graph.py
  class KnowledgeGraphService (line 13) | class KnowledgeGraphService:
    method __init__ (line 16) | def __init__(self, db_path: Path):
    method add_node (line 21) | def add_node(self, node: Node) -> None:
    method get_node (line 31) | def get_node(self, node_id: str) -> Node | None:
    method list_nodes (line 40) | def list_nodes(self, node_type: str | None = None) -> list[Node]:
    method add_edge (line 51) | def add_edge(self, edge: Edge) -> None:
    method get_edges (line 60) | def get_edges(self, node_id: str, direction: str = "out") -> list[Edge]:
    method neighbors (line 77) | def neighbors(self, node_id: str) -> list[Node]:
    method delete_node (line 86) | def delete_node(self, node_id: str) -> None:
  function _row_to_node (line 96) | def _row_to_node(r: sqlite3.Row) -> Node:
  function _row_to_edge (line 104) | def _row_to_edge(r: sqlite3.Row) -> Edge:

FILE: maggy/maggy/cikg/models.py
  class Node (line 21) | class Node:
    method __post_init__ (line 35) | def __post_init__(self) -> None:
  class Edge (line 41) | class Edge:
    method __post_init__ (line 50) | def __post_init__(self) -> None:
  class MarketScore (line 56) | class MarketScore:

FILE: maggy/maggy/cikg/queries.py
  function find_gaps (line 9) | def find_gaps(graph: KnowledgeGraphService, feature_name: str) -> Market...
  function find_gaps_raw (line 29) | def find_gaps_raw(graph: KnowledgeGraphService, feature: str) -> list[di...
  function compare_entities (line 42) | def compare_entities(graph: KnowledgeGraphService, id_a: str, id_b: str)...
  function get_landscape (line 59) | def get_landscape(graph: KnowledgeGraphService) -> dict:
  function get_segment_landscape (line 72) | def get_segment_landscape(graph: KnowledgeGraphService, segment: str) ->...
  function _matching_ids (line 103) | def _matching_ids(graph: KnowledgeGraphService, node_type: str, query: s...
  function _matching_nodes (line 107) | def _matching_nodes(graph: KnowledgeGraphService, node_type: str, query:...
  function _targets_for (line 112) | def _targets_for(graph: KnowledgeGraphService, node_id: str, edge_type: ...
  function _threat_level (line 116) | def _threat_level(have_it: int, total: int) -> str:
  function _recommend (line 125) | def _recommend(feature: str, have: int, total: int, threat: str) -> str:
  function _empty_landscape (line 133) | def _empty_landscape(segment: str) -> dict:

FILE: maggy/maggy/cikg/storage.py
  function _connect (line 35) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:

FILE: maggy/maggy/cli.py
  function _ensure (line 28) | def _ensure() -> bool:
  function main (line 38) | def main(ctx: typer.Context) -> None:
  function serve (line 52) | def serve() -> None:
  function status (line 59) | def status(json_out: bool = typer.Option(False, "--json")) -> None:
  function inbox (line 67) | def inbox(
  function sessions (line 83) | def sessions(json_out: bool = typer.Option(False, "--json")) -> None:
  function chat (line 91) | def chat(
  function spawn (line 102) | def spawn(
  function ps (line 117) | def ps() -> None:
  function kill (line 125) | def kill(
  function execute (line 135) | def execute(
  function route (line 151) | def route(
  function budget (line 163) | def budget(json_out: bool = typer.Option(False, "--json")) -> None:
  function models (line 171) | def models(json_out: bool = typer.Option(False, "--json")) -> None:
  function competitors (line 179) | def competitors(
  function process (line 198) | def process(
  function config (line 209) | def config(json_out: bool = typer.Option(False, "--json")) -> None:

FILE: maggy/maggy/cli_chat.py
  function detect_project (line 22) | def detect_project(client) -> str | None:
  function run_chat (line 27) | def run_chat(
  function _find_or_create (line 40) | def _find_or_create(client, project: str) -> tuple[dict, bool]:
  function _show_resume_info (line 47) | def _show_resume_info(client, sid: str, wd: str) -> None:
  function _repl_loop (line 59) | def _repl_loop(client, state: SessionState, routed: bool) -> None:
  function _parse_blast (line 107) | def _parse_blast(text: str) -> int | None:
  function _stream_chunks (line 120) | def _stream_chunks(chunks) -> None:
  function _call_safe (line 154) | def _call_safe(fn, default=None):
  function _handle_screenshot (line 161) | def _handle_screenshot(text: str) -> None:
  function _show_routing (line 174) | def _show_routing(chunk: dict) -> None:
  function _show_history (line 178) | def _show_history(client, session_id: str) -> None:
  function _show_sessions (line 189) | def _show_sessions(client) -> None:

FILE: maggy/maggy/cli_client.py
  class MaggyClient (line 24) | class MaggyClient:
    method __init__ (line 27) | def __init__(self, base_url: str = DEFAULT_URL):
    method _check_health (line 32) | def _check_health(self) -> bool:
    method _get_port (line 42) | def _get_port(self) -> int:
    method _kill_stale_port (line 46) | def _kill_stale_port(self) -> None:
    method _start_server (line 63) | def _start_server(self) -> None:
    method ensure_server (line 72) | def ensure_server(self) -> bool:
    method _handle_error (line 87) | def _handle_error(self, r: httpx.Response) -> None:
    method get (line 100) | def get(self, path: str, **params) -> dict | list:
    method post (line 109) | def post(self, path: str, body: dict) -> dict:
    method health (line 118) | def health(self) -> dict:
    method inbox (line 121) | def inbox(self, refresh: bool = False) -> dict:
    method activity (line 124) | def activity(self) -> dict:
    method route (line 127) | def route(self, blast: int, task_type: str) -> dict:
    method budget_summary (line 134) | def budget_summary(self) -> dict:
    method competitors_news (line 137) | def competitors_news(self, limit: int = 50) -> list:
    method competitors_briefing (line 140) | def competitors_briefing(self) -> dict:
    method models_heatmap (line 143) | def models_heatmap(self) -> list:
    method routing_rules (line 146) | def routing_rules(self) -> dict:
    method budget_by_provider (line 149) | def budget_by_provider(self) -> list:
    method process_health (line 152) | def process_health(self, project: str) -> dict:
    method config (line 155) | def config(self) -> dict:
    method execute (line 158) | def execute(self, task_id: str, mode: str) -> dict:
    method sessions (line 164) | def sessions(self) -> list:
    method chat_create (line 169) | def chat_create(self, project_key: str) -> dict:
    method chat_sessions (line 175) | def chat_sessions(self) -> list:
    method chat_history (line 178) | def chat_history(self, session_id: str) -> dict:
    method chat_send_stream (line 181) | def chat_send_stream(
    method chat_send_routed (line 198) | def chat_send_routed(
    method detect_project (line 220) | def detect_project(self, cwd: str) -> str | None:
    method spawn (line 233) | def spawn(self, task: str, project: str) -> dict:
    method all_sessions (line 240) | def all_sessions(self) -> list:
    method kill_session (line 265) | def kill_session(self, session_id: str) -> dict:
    method monitor_status (line 276) | def monitor_status(self) -> dict:
    method monitor_start (line 279) | def monitor_start(self) -> dict:
    method monitor_stop (line 282) | def monitor_stop(self) -> dict:
    method health_dashboard (line 287) | def health_dashboard(self) -> dict:
    method engram_diagnostics (line 290) | def engram_diagnostics(self) -> dict:

FILE: maggy/maggy/cli_output.py
  function _is_pipe (line 15) | def _is_pipe() -> bool:
  function dump_json (line 19) | def dump_json(data) -> None:
  function render_health (line 27) | def render_health(data: dict) -> None:
  function render_inbox (line 42) | def render_inbox(data: dict) -> None:
  function render_sessions (line 66) | def render_sessions(data: dict | list) -> None:
  function _model_name (line 93) | def _model_name(val) -> str:
  function render_route (line 99) | def render_route(data: dict) -> None:
  function render_budget (line 119) | def render_budget(data: dict) -> None:
  function render_competitors (line 152) | def render_competitors(news: list) -> None:
  function render_models (line 172) | def render_models(heatmap: list) -> None:

FILE: maggy/maggy/cli_repl_cmds.py
  function _call (line 18) | def _call(fn, d=None):
  class SessionState (line 26) | class SessionState:
  function dispatch (line 34) | def dispatch(cmd: str, client, state: SessionState) -> bool:
  function cmd_stats (line 57) | def cmd_stats(client) -> None:
  function cmd_budget (line 75) | def cmd_budget(client) -> None:
  function cmd_route (line 95) | def cmd_route(client) -> None:
  function cmd_models (line 117) | def cmd_models(client) -> None:
  function cmd_use (line 135) | def cmd_use(args: str, state: SessionState) -> None:
  function cmd_config (line 149) | def cmd_config(client) -> None:
  function cmd_claude_md (line 164) | def cmd_claude_md(state: SessionState) -> None:
  function cmd_health (line 175) | def cmd_health(client) -> None:
  function cmd_help (line 199) | def cmd_help() -> None:

FILE: maggy/maggy/cli_sessions.py
  function spawn_session (line 11) | def spawn_session(client, task: str, project: str) -> None:
  function list_all (line 21) | def list_all(client) -> None:
  function kill_session (line 44) | def kill_session(client, session_id: str) -> None:

FILE: maggy/maggy/cli_welcome.py
  function render_welcome (line 16) | def render_welcome(
  function _add_project_rows (line 33) | def _add_project_rows(
  function _add_system_rows (line 49) | def _add_system_rows(
  function _add_health_row (line 69) | def _add_health_row(t: Table, client) -> None:
  function _safe_call (line 79) | def _safe_call(fn):
  function _shorten (line 87) | def _shorten(path: str, max_len: int) -> str:

FILE: maggy/maggy/config.py
  function _default_storage_path (line 20) | def _default_storage_path() -> str:
  function _safe_storage_path (line 24) | def _safe_storage_path(path: str | Path) -> str:
  class GitHubConfig (line 39) | class GitHubConfig:
  class AsanaConfig (line 47) | class AsanaConfig:
  class LinearConfig (line 54) | class LinearConfig:
  class IssueTrackerConfig (line 60) | class IssueTrackerConfig:
  class CodebaseConfig (line 68) | class CodebaseConfig:
  class ProjectConfig (line 74) | class ProjectConfig:
  class OKRItem (line 84) | class OKRItem:
  class OKRConfig (line 91) | class OKRConfig:
  class CompetitorsConfig (line 97) | class CompetitorsConfig:
  class AIConfig (line 103) | class AIConfig:
  class StorageConfig (line 111) | class StorageConfig:
  class DashboardConfig (line 117) | class DashboardConfig:
  class OrgConfig (line 125) | class OrgConfig:
  class BootstrapConfig (line 131) | class BootstrapConfig:
  class ModelTierConfig (line 136) | class ModelTierConfig:
  class BudgetConfig (line 146) | class BudgetConfig:
  class RoutingConfig (line 155) | class RoutingConfig:
  class MeshConfig (line 161) | class MeshConfig:
  class HeartbeatConfig (line 175) | class HeartbeatConfig:
  class MaggyConfig (line 184) | class MaggyConfig:
    method codebase_paths (line 200) | def codebase_paths(self) -> dict[str, Path]:
    method resolve_bootstrap_path (line 204) | def resolve_bootstrap_path(self) -> Path | None:
  function _merge_env (line 214) | def _merge_env(cfg: MaggyConfig) -> MaggyConfig:
  function _git_credential_token (line 228) | def _git_credential_token() -> str:
  function _from_dict (line 234) | def _from_dict(data: dict[str, Any]) -> MaggyConfig:
  function _has_provider_credentials (line 297) | def _has_provider_credentials(cfg: MaggyConfig) -> bool:
  function _has_cli_history (line 308) | def _has_cli_history(
  function auto_configure (line 319) | def auto_configure(
  function _repos_for_org (line 344) | def _repos_for_org(
  function load (line 357) | def load(refresh: bool = False) -> MaggyConfig:
  function save (line 373) | def save(cfg: MaggyConfig) -> None:
  function is_configured (line 390) | def is_configured() -> bool:

FILE: maggy/maggy/contracts/generator.py
  class ContractGenerator (line 8) | class ContractGenerator:
    method from_postcondition (line 9) | def from_postcondition(self, postcondition: str, symbol: str) -> str:
  function _test_name (line 20) | def _test_name(symbol: str) -> str:

FILE: maggy/maggy/coordination/lock_manager.py
  function _connect (line 27) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class LockManager (line 39) | class LockManager:
    method __init__ (line 40) | def __init__(self, db_path: Path):
    method acquire (line 44) | def acquire(self, file_path: str, agent_id: str) -> bool:
    method release (line 71) | def release(self, file_path: str, agent_id: str) -> bool:
    method release_all (line 81) | def release_all(self, agent_id: str) -> int:
    method conflicts (line 88) | def conflicts(self, file_paths: list[str]) -> list[str]:
    method _expire_locks (line 101) | def _expire_locks(self, conn: sqlite3.Connection, now: str) -> None:
    method _init_db (line 104) | def _init_db(self) -> None:
  function _now (line 109) | def _now() -> str:
  function _timestamps (line 113) | def _timestamps() -> tuple[str, str]:

FILE: maggy/maggy/deploy.py
  class DeploySession (line 13) | class DeploySession:
  class DeployService (line 28) | class DeployService:
    method __init__ (line 31) | def __init__(self):
    method create_session (line 34) | def create_session(
    method get_session (line 51) | def get_session(self, sid: str) -> DeploySession | None:
    method list_sessions (line 54) | def list_sessions(self) -> list[DeploySession]:
    method update_status (line 57) | def update_status(
    method teardown (line 69) | def teardown(self, sid: str) -> bool:

FILE: maggy/maggy/discovery.py
  class DiscoveryResult (line 25) | class DiscoveryResult:
  function discover_clis (line 46) | def discover_clis() -> dict[str, str]:
  function discover_cli_auth (line 56) | def discover_cli_auth() -> dict[str, bool]:
  function _has_json_key (line 74) | def _has_json_key(path: Path, key: str) -> bool:
  function discover_git_token (line 85) | def discover_git_token() -> str:
  function discover_repos (line 101) | def discover_repos(
  function _scan_dir (line 117) | def _scan_dir(
  function discover_active_projects (line 141) | def discover_active_projects(
  function discover_env_tokens (line 171) | def discover_env_tokens() -> dict[str, bool]:
  function infer_github_org (line 192) | def infer_github_org(repo_path: Path) -> str:
  function _parse_org_from_url (line 206) | def _parse_org_from_url(url: str) -> str:
  function discover_all_orgs (line 217) | def discover_all_orgs(repos: list[dict]) -> list[str]:
  function full_discovery (line 227) | def full_discovery(

FILE: maggy/maggy/engram/diagnostics.py
  class AmnesiaProfile (line 11) | class AmnesiaProfile:
    method health_score (line 23) | def health_score(self) -> float:
  function diagnose (line 39) | def diagnose(

FILE: maggy/maggy/engram/record.py
  class Origin (line 10) | class Origin(str, Enum):
  class Validity (line 16) | class Validity(str, Enum):
  class EngramRecord (line 23) | class EngramRecord:
    method is_active (line 43) | def is_active(self) -> bool:
    method supersede (line 46) | def supersede(self) -> None:

FILE: maggy/maggy/engram/retrieval.py
  class EngramRetrieval (line 9) | class EngramRetrieval:
    method __init__ (line 12) | def __init__(self, store: EngramStore):
    method by_namespace (line 15) | def by_namespace(
    method by_type (line 23) | def by_type(
    method by_keyword (line 31) | def by_keyword(
    method by_tag (line 45) | def by_tag(
    method recent (line 58) | def recent(self, limit: int = 20) -> list[EngramRecord]:

FILE: maggy/maggy/engram/seed.py
  function seed_if_empty (line 28) | def seed_if_empty(store: EngramStore) -> None:

FILE: maggy/maggy/engram/store.py
  function _connect (line 37) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class EngramStore (line 49) | class EngramStore:
    method __init__ (line 52) | def __init__(self, db_path: Path):
    method write (line 57) | def write(self, record: EngramRecord) -> None:
    method get (line 78) | def get(
    method query (line 91) | def query(
    method count (line 121) | def count(
    method _row_to_record (line 137) | def _row_to_record(

FILE: maggy/maggy/escalation/protocol.py
  class EscalationPacket (line 32) | class EscalationPacket:
  function _connect (line 45) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class Escalator (line 57) | class Escalator:
    method __init__ (line 58) | def __init__(self, db_path: Path):
    method escalate (line 62) | def escalate(
    method resolve (line 74) | def resolve(self, escalation_id: str, guidance: str) -> EscalationPacket:
    method list_pending (line 89) | def list_pending(self) -> list[EscalationPacket]:
    method get (line 96) | def get(self, escalation_id: str) -> EscalationPacket | None:
    method _init_db (line 104) | def _init_db(self) -> None:
  function _build_packet (line 109) | def _build_packet(
  function _dict_field (line 125) | def _dict_field(context: dict[str, object], key: str) -> dict[str, object]:
  function _list_field (line 130) | def _list_field(context: dict[str, object], key: str) -> list[str]:
  function _serialize (line 135) | def _serialize(packet: EscalationPacket) -> tuple[object, ...]:
  function _safe_json (line 149) | def _safe_json(raw: str, fallback: object) -> object:
  function _from_row (line 156) | def _from_row(row: sqlite3.Row) -> EscalationPacket:

FILE: maggy/maggy/event_spine/emitter.py
  class EventEmitter (line 14) | class EventEmitter:
    method __init__ (line 17) | def __init__(self, store: EventStore):
    method emit (line 20) | def emit(self, event: object) -> str:
    method query (line 34) | def query(
    method trace (line 49) | def trace(self, task_id: str) -> list[dict]:
    method count (line 55) | def count(

FILE: maggy/maggy/event_spine/events.py
  class IntentEvent (line 11) | class IntentEvent:
  class BindingEvent (line 23) | class BindingEvent:
  class ExecutionEvent (line 36) | class ExecutionEvent:
  class MemoryEvent (line 50) | class MemoryEvent:
  class PersistenceEvent (line 62) | class PersistenceEvent:
  class OutcomeEvent (line 76) | class OutcomeEvent:
  class MutationEvent (line 88) | class MutationEvent:
  class MeshEvent (line 102) | class MeshEvent:

FILE: maggy/maggy/event_spine/header.py
  function _uuid (line 10) | def _uuid() -> str:
  function _now (line 14) | def _now() -> str:
  class EventHeader (line 19) | class EventHeader:

FILE: maggy/maggy/event_spine/store.py
  function _connect (line 39) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class EventStore (line 51) | class EventStore:
    method __init__ (line 54) | def __init__(self, db_path: Path):
    method _init_db (line 58) | def _init_db(self) -> None:
    method write (line 62) | def write(
    method query (line 84) | def query(
    method count (line 118) | def count(
    method archive_old (line 144) | def archive_old(

FILE: maggy/maggy/fatigue.py
  class FatigueProfile (line 13) | class FatigueProfile:
    method raw_utilization (line 23) | def raw_utilization(self) -> float:
    method fatigue_score (line 30) | def fatigue_score(self) -> float:
    method should_checkpoint (line 40) | def should_checkpoint(self, threshold: float = 0.6) -> bool:
  function create_profile (line 55) | def create_profile(model: str) -> FatigueProfile:
  function compare_fatigue (line 61) | def compare_fatigue(

FILE: maggy/maggy/forge/connector.py
  class ForgeStatus (line 23) | class ForgeStatus:
  class ForgeConnector (line 32) | class ForgeConnector:
    method __init__ (line 35) | def __init__(
    method available (line 46) | def available(self) -> bool:
    method status (line 49) | def status(self) -> ForgeStatus:
    method search_tools (line 58) | def search_tools(self, query: str) -> list[dict]:
    method report_gap (line 71) | def report_gap(self, capability: str) -> dict:
    method get_gaps (line 84) | def get_gaps(self) -> list[dict]:

FILE: maggy/maggy/forge/detector.py
  class GapRecord (line 16) | class GapRecord:
  class GapDetector (line 24) | class GapDetector:
    method __init__ (line 27) | def __init__(self, threshold: int = TRIGGER_THRESHOLD):
    method record_gap (line 32) | def record_gap(self, capability: str) -> bool:
    method list_gaps (line 44) | def list_gaps(self) -> list[GapRecord]:
    method top_gaps (line 55) | def top_gaps(self, n: int = 5) -> list[GapRecord]:
    method reset (line 59) | def reset(self, capability: str) -> None:

FILE: maggy/maggy/forge/registry.py
  class ToolInfo (line 15) | class ToolInfo:
  class ForgeRegistry (line 25) | class ForgeRegistry:
    method __init__ (line 28) | def __init__(self, forge_path: Path | None = None):
    method _load_registry (line 33) | def _load_registry(self) -> None:
    method search (line 43) | def search(self, query: str) -> list[ToolInfo]:
    method get (line 51) | def get(self, slug: str) -> ToolInfo | None:
    method list_all (line 54) | def list_all(self) -> list[ToolInfo]:
    method set_enabled (line 57) | def set_enabled(self, slug: str, enabled: bool) -> bool:
    method count (line 65) | def count(self) -> int:
  function _parse_registry (line 69) | def _parse_registry(path: Path) -> dict[str, ToolInfo]:

FILE: maggy/maggy/heartbeat/jobs.py
  function refresh_history (line 13) | async def refresh_history(app) -> None:
  function expire_engrams (line 25) | async def expire_engrams(app) -> None:
  function _is_expired (line 42) | def _is_expired(rec, now) -> bool:
  function self_improve (line 59) | async def self_improve(app) -> None:
  function mesh_heartbeat (line 71) | async def mesh_heartbeat(app) -> None:
  function collect_signals (line 89) | async def collect_signals(app) -> None:

FILE: maggy/maggy/heartbeat/scheduler.py
  class Job (line 17) | class Job:
    method is_due (line 26) | def is_due(self) -> bool:
  class HeartbeatScheduler (line 34) | class HeartbeatScheduler:
    method __init__ (line 35) | def __init__(self) -> None:
    method register (line 39) | def register(
    method tick (line 48) | async def tick(self) -> None:
    method _run_job (line 54) | async def _run_job(self, job: Job) -> None:
    method trigger (line 64) | async def trigger(self, name: str) -> dict:
    method start (line 71) | async def start(self) -> None:
    method stop (line 75) | async def stop(self) -> None:
    method _loop (line 85) | async def _loop(self) -> None:
    method status (line 90) | def status(self) -> list[dict]:

FILE: maggy/maggy/history/analyzer.py
  function build_report (line 18) | def build_report(
  function aggregate_by_provider (line 40) | def aggregate_by_provider(
  function aggregate_by_project (line 66) | def aggregate_by_project(
  function compute_time_distribution (line 91) | def compute_time_distribution(
  function extract_top_topics (line 117) | def extract_top_topics(
  function detect_patterns (line 128) | def detect_patterns(
  function _detect_provider_dominance (line 141) | def _detect_provider_dominance(
  function _detect_session_stats (line 156) | def _detect_session_stats(
  function _detect_project_focus (line 181) | def _detect_project_focus(
  function _merge_topics (line 195) | def _merge_topics(

FILE: maggy/maggy/history/models.py
  class SessionEntry (line 10) | class SessionEntry:
    method duration_minutes (line 26) | def duration_minutes(self) -> float | None:
  class ProjectActivity (line 39) | class ProjectActivity:
  class ProviderUsage (line 51) | class ProviderUsage:
  class TimeDistribution (line 62) | class TimeDistribution:
  class HistoryReport (line 71) | class HistoryReport:
  function _now_iso (line 89) | def _now_iso() -> str:

FILE: maggy/maggy/history/parsers/base.py
  class HistoryParser (line 10) | class HistoryParser(ABC):
    method is_available (line 16) | def is_available(self) -> bool:
    method parse_sessions (line 21) | def parse_sessions(
    method session_count (line 28) | def session_count(self) -> int:

FILE: maggy/maggy/history/parsers/claude.py
  function _millis_to_iso (line 18) | def _millis_to_iso(ms: int | float) -> str:
  function _read_jsonl (line 24) | def _read_jsonl(path: Path) -> list[dict]:
  function _extract_topics (line 43) | def _extract_topics(prompts: list[str]) -> list[str]:
  class ClaudeHistoryParser (line 55) | class ClaudeHistoryParser(HistoryParser):
    method __init__ (line 60) | def __init__(self, claude_dir: Path | None = None):
    method is_available (line 65) | def is_available(self) -> bool:
    method session_count (line 69) | def session_count(self) -> int:
    method parse_sessions (line 75) | def parse_sessions(
    method _group_by_session (line 89) | def _group_by_session(
    method _build_entry (line 99) | def _build_entry(
    method _slug (line 133) | def _slug(self, project_path: str) -> str:
    method _find_transcript (line 139) | def _find_transcript(
    method _parse_transcript (line 159) | def _parse_transcript(

FILE: maggy/maggy/history/parsers/codex.py
  function _seconds_to_iso (line 18) | def _seconds_to_iso(ts: int | float) -> str:
  function _read_jsonl (line 24) | def _read_jsonl(path: Path) -> list[dict]:
  function _extract_topics (line 43) | def _extract_topics(texts: list[str]) -> list[str]:
  class CodexHistoryParser (line 55) | class CodexHistoryParser(HistoryParser):
    method __init__ (line 60) | def __init__(self, codex_dir: Path | None = None):
    method is_available (line 65) | def is_available(self) -> bool:
    method session_count (line 69) | def session_count(self) -> int:
    method parse_sessions (line 75) | def parse_sessions(
    method _group_prompts (line 100) | def _group_prompts(
    method _build_entry (line 110) | def _build_entry(

FILE: maggy/maggy/history/parsers/kimi.py
  function _float_to_iso (line 17) | def _float_to_iso(ts: float) -> str:
  function _read_jsonl (line 23) | def _read_jsonl(path: Path) -> list[dict]:
  function _extract_topics (line 42) | def _extract_topics(texts: list[str]) -> list[str]:
  class KimiHistoryParser (line 54) | class KimiHistoryParser(HistoryParser):
    method __init__ (line 59) | def __init__(self, kimi_dir: Path | None = None):
    method is_available (line 64) | def is_available(self) -> bool:
    method session_count (line 68) | def session_count(self) -> int:
    method parse_sessions (line 71) | def parse_sessions(
    method _find_session_dirs (line 82) | def _find_session_dirs(self) -> list[Path]:
    method _parse_session_dir (line 99) | def _parse_session_dir(
    method _parse_wire (line 136) | def _parse_wire(self, session_dir: Path) -> dict:

FILE: maggy/maggy/history/service.py
  class HistoryService (line 18) | class HistoryService:
    method __init__ (line 21) | def __init__(
    method analyze (line 37) | def analyze(self) -> HistoryReport:
    method _collect_sessions (line 55) | def _collect_sessions(self) -> list:
    method get_report (line 79) | def get_report(self) -> dict | None:
    method get_sessions (line 83) | def get_sessions(
    method available_providers (line 91) | def available_providers(self) -> list[str]:

FILE: maggy/maggy/history/store.py
  function _connect (line 45) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class HistoryStore (line 57) | class HistoryStore:
    method __init__ (line 60) | def __init__(self, db_path: Path):
    method save_sessions (line 65) | def save_sessions(
    method load_sessions (line 93) | def load_sessions(
    method save_report (line 117) | def save_report(self, report: HistoryReport) -> None:
    method load_latest_report (line 128) | def load_latest_report(self) -> dict | None:
    method _row_to_dict (line 139) | def _row_to_dict(self, r: sqlite3.Row) -> dict:

FILE: maggy/maggy/improve/analyzer.py
  function analyze_routing (line 14) | def analyze_routing(signals: SignalBundle) -> list[Recommendation]:
  function analyze_failures (line 32) | def analyze_failures(signals: SignalBundle) -> list[Recommendation]:
  function analyze_usage (line 46) | def analyze_usage(signals: SignalBundle) -> list[Recommendation]:
  function analyze_gaps (line 69) | def analyze_gaps(signals: SignalBundle) -> list[Recommendation]:
  function analyze_memory (line 86) | def analyze_memory(signals: SignalBundle) -> list[Recommendation]:
  function analyze_cost (line 100) | def analyze_cost(signals: SignalBundle) -> list[Recommendation]:
  function analyze_all (line 114) | def analyze_all(signals: SignalBundle) -> list[Recommendation]:

FILE: maggy/maggy/improve/models.py
  class Recommendation (line 9) | class Recommendation:
  class SignalBundle (line 18) | class SignalBundle:
  class ImprovementReport (line 29) | class ImprovementReport:

FILE: maggy/maggy/improve/service.py
  class Introspector (line 15) | class Introspector:
    method __init__ (line 18) | def __init__(self, app_state) -> None:
    method analyze (line 22) | def analyze(self) -> ImprovementReport:
    method get_report (line 31) | def get_report(self) -> ImprovementReport | None:
    method _build_report (line 35) | def _build_report(self, signals, recs) -> ImprovementReport:
    method _health_summary (line 56) | def _health_summary(self, s: SignalBundle) -> dict:
    method _persist (line 71) | def _persist(self, report: ImprovementReport) -> None:
    method _write_engram (line 80) | def _write_engram(self, engram, report) -> None:
    method _emit_mutations (line 95) | def _emit_mutations(self, events, report) -> None:

FILE: maggy/maggy/improve/signals.py
  function collect_routing (line 15) | def collect_routing(routing) -> dict:
  function collect_events (line 26) | def collect_events(events) -> dict:
  function collect_history (line 42) | def collect_history(history) -> dict:
  function collect_forge (line 54) | def collect_forge(forge) -> dict:
  function collect_engram (line 60) | def collect_engram(engram) -> dict:
  function collect_budget (line 72) | def collect_budget(budget) -> dict:
  function collect_all (line 77) | def collect_all(app_state) -> SignalBundle:

FILE: maggy/maggy/lexon/disambiguate.py
  class DisambiguationResult (line 12) | class DisambiguationResult:
  function disambiguate (line 21) | def disambiguate(

FILE: maggy/maggy/lexon/personalization.py
  class UserSignals (line 10) | class UserSignals:
  class PersonalizationEngine (line 30) | class PersonalizationEngine:
    method __init__ (line 33) | def __init__(self):
    method record_use (line 36) | def record_use(self, tool: str) -> None:
    method record_correction (line 40) | def record_correction(
    method record_alias (line 48) | def record_alias(
    method record_rejection (line 56) | def record_rejection(self, tool: str) -> None:
    method get_preferred (line 60) | def get_preferred(self, phrase: str) -> str | None:
    method top_tools (line 66) | def top_tools(self, n: int = 5) -> list[str]:
    method signals (line 73) | def signals(self) -> UserSignals:

FILE: maggy/maggy/lexon/record.py
  class LexonRecord (line 10) | class LexonRecord:
    method is_ambiguous (line 25) | def is_ambiguous(self) -> bool:
    method needs_user_input (line 29) | def needs_user_input(self) -> bool:

FILE: maggy/maggy/lexon/router.py
  class LexonRouter (line 24) | class LexonRouter:
    method __init__ (line 31) | def __init__(self, config: dict[str, object] | None = None):
    method route (line 37) | def route(self, phrase: str) -> LexonRecord:
    method learn (line 52) | def learn(self, phrase: str, tool: str) -> None:
    method terminology (line 58) | def terminology(self) -> TerminologyMap:
    method personalization (line 62) | def personalization(self) -> PersonalizationEngine:
    method _load_tool_manifest (line 65) | def _load_tool_manifest(self) -> dict[str, list[str]]:
    method _llm_classify (line 75) | def _llm_classify(self, phrase: str) -> LexonRecord:
    method _route_tier1 (line 82) | def _route_tier1(self, phrase: str) -> LexonRecord | None:
    method _resolve_manifest_match (line 89) | def _resolve_manifest_match(
    method _keyword_confidence (line 108) | def _keyword_confidence(self, candidates: list[str]) -> float:
    method _top2_gap (line 115) | def _top2_gap(self, candidates: list[str]) -> float:

FILE: maggy/maggy/lexon/terminology.py
  class TermEntry (line 14) | class TermEntry:
  class TerminologyMap (line 34) | class TerminologyMap:
    method __init__ (line 37) | def __init__(
    method _build_index (line 54) | def _build_index(self) -> dict[str, str]:
    method resolve (line 64) | def resolve(self, word: str) -> str | None:
    method add_alias (line 68) | def add_alias(self, canonical: str, alias: str) -> bool:
    method list_terms (line 77) | def list_terms(self) -> list[TermEntry]:

FILE: maggy/maggy/main.py
  function _init_tier1 (line 61) | def _init_tier1(app: FastAPI, cfg) -> None:
  function _init_mesh (line 97) | def _init_mesh(app: FastAPI, cfg) -> None:
  function _set_mode (line 115) | def _set_mode(app: FastAPI, cfg) -> None:
  function _start_heartbeat (line 130) | async def _start_heartbeat(app: FastAPI) -> None:
  function lifespan (line 152) | async def lifespan(app: FastAPI):
  function _bootstrap (line 161) | async def _bootstrap(app: FastAPI) -> None:
  function _seed_cikg (line 186) | def _seed_cikg(cikg, cfg) -> None:
  function _add_language_nodes (line 205) | def _add_language_nodes(cikg, codebase_key, path, now) -> None:
  class _NoCacheStatic (line 251) | class _NoCacheStatic(BaseHTTPMiddleware):
    method dispatch (line 254) | async def dispatch(
  function create_app (line 275) | def create_app() -> FastAPI:
  function reconfigure (line 315) | def reconfigure(app: FastAPI) -> None:
  function _print_banner (line 329) | def _print_banner(host: str, port: int) -> None:
  function main (line 352) | def main() -> None:

FILE: maggy/maggy/mesh/discovery.py
  class PeerInfo (line 10) | class PeerInfo:
  class PeerRegistry (line 26) | class PeerRegistry:
    method __init__ (line 29) | def __init__(self, store=None, org: str = ""):
    method _load_from_store (line 36) | def _load_from_store(self) -> None:
    method register (line 48) | def register(self, peer: PeerInfo) -> None:
    method unregister (line 56) | def unregister(self, peer_id: str) -> bool:
    method get (line 64) | def get(self, peer_id: str) -> PeerInfo | None:
    method list_peers (line 67) | def list_peers(self) -> list[PeerInfo]:
    method update_seen (line 70) | def update_seen(self, peer_id: str) -> None:
    method count (line 83) | def count(self) -> int:

FILE: maggy/maggy/mesh/git_discovery.py
  class Announcement (line 20) | class Announcement:
  function _headers (line 30) | def _headers(token: str) -> dict[str, str]:
  function ensure_mesh_repo (line 38) | async def ensure_mesh_repo(
  function announce (line 69) | async def announce(
  function read_peers (line 112) | async def read_peers(
  function _decode_peer (line 139) | def _decode_peer(item: dict) -> dict | None:
  function remove_announcement (line 150) | async def remove_announcement(

FILE: maggy/maggy/mesh/manager.py
  class MeshManager (line 21) | class MeshManager:
    method __init__ (line 24) | def __init__(self, cfg, store: MeshStore) -> None:
    method add_network (line 29) | def add_network(self, org: str) -> Network:
    method get_network (line 36) | def get_network(self, org: str) -> Network | None:
    method list_networks (line 39) | def list_networks(self) -> list[dict]:
    method total_peers (line 43) | def total_peers(self) -> int:
    method discover (line 48) | async def discover(self, token: str) -> dict:
    method announce_all (line 69) | async def announce_all(self, token: str) -> dict:
    method setup_repos (line 85) | async def setup_repos(self, token: str) -> dict:
    method _resolve_address (line 93) | def _resolve_address(self) -> str:

FILE: maggy/maggy/mesh/memory.py
  class MemoryType (line 10) | class MemoryType(str, Enum):
  class SharedMemory (line 18) | class SharedMemory:
    method is_trusted (line 33) | def is_trusted(self) -> bool:

FILE: maggy/maggy/mesh/network.py
  class Network (line 18) | class Network:
    method status (line 27) | def status(self) -> dict:
  function build_network (line 36) | def build_network(

FILE: maggy/maggy/mesh/org_scanner.py
  function scan_orgs (line 10) | def scan_orgs(home: Path | None = None) -> list[str]:
  function effective_orgs (line 21) | def effective_orgs(

FILE: maggy/maggy/mesh/protocol.py
  class MessageType (line 11) | class MessageType(str, Enum):
  class MeshMessage (line 22) | class MeshMessage:
    method serialize (line 34) | def serialize(self) -> str:
    method deserialize (line 38) | def deserialize(cls, data: str) -> MeshMessage:
  function create_hello (line 43) | def create_hello(peer_id: str, name: str) -> MeshMessage:
  function create_share (line 51) | def create_share(

FILE: maggy/maggy/mesh/provenance.py
  class Provenance (line 13) | class Provenance:
    method effective_confidence (line 26) | def effective_confidence(self) -> float:
    method add_hop (line 30) | def add_hop(self) -> Provenance:

FILE: maggy/maggy/mesh/publisher.py
  function collect_scores (line 8) | def collect_scores(routing, peer_id: str) -> list[SharedMemory]:
  function collect_gaps (line 25) | def collect_gaps(forge, peer_id: str) -> list[SharedMemory]:
  function collect_policies (line 39) | def collect_policies(introspector, peer_id: str) -> list[SharedMemory]:
  function collect_all_shares (line 59) | def collect_all_shares(app_state, peer_id: str) -> list[SharedMemory]:

FILE: maggy/maggy/mesh/quarantine.py
  class QuarantineEntry (line 10) | class QuarantineEntry:
  class QuarantineStore (line 25) | class QuarantineStore:
    method __init__ (line 28) | def __init__(self, store=None, org: str = ""):
    method _load_from_store (line 35) | def _load_from_store(self) -> None:
    method quarantine (line 45) | def quarantine(
    method get (line 62) | def get(self, key: str) -> QuarantineEntry | None:
    method list_all (line 65) | def list_all(self) -> list[QuarantineEntry]:
    method promote (line 68) | def promote(self, key: str) -> QuarantineEntry | None:
    method reject (line 75) | def reject(self, key: str) -> bool:
    method count (line 85) | def count(self) -> int:

FILE: maggy/maggy/mesh/store.py
  function _now (line 44) | def _now() -> str:
  class MeshStore (line 48) | class MeshStore:
    method __init__ (line 51) | def __init__(self, db_path: Path) -> None:
    method upsert_peer (line 66) | def upsert_peer(
    method get_peer (line 79) | def get_peer(
    method list_peers (line 90) | def list_peers(
    method remove_peer (line 105) | def remove_peer(
    method write_memory (line 119) | def write_memory(
    method list_memories (line 134) | def list_memories(self, org: str) -> list[dict]:
    method quarantine_item (line 147) | def quarantine_item(
    method promote_item (line 160) | def promote_item(
    method list_quarantined (line 172) | def list_quarantined(self, org: str) -> list[dict]:
    method close (line 183) | def close(self) -> None:

FILE: maggy/maggy/mesh/sync.py
  class SyncResult (line 17) | class SyncResult:
  class SyncEngine (line 25) | class SyncEngine:
    method __init__ (line 28) | def __init__(
    method _load_from_store (line 39) | def _load_from_store(self) -> None:
    method sync_incoming (line 49) | def sync_incoming(
    method _accept (line 69) | def _accept(self, mem: SharedMemory) -> None:
    method promote_from_quarantine (line 77) | def promote_from_quarantine(self, key: str) -> bool:
    method get_local (line 92) | def get_local(self, key: str) -> SharedMemory | None:
    method list_local (line 95) | def list_local(self) -> list[SharedMemory]:
    method local_count (line 99) | def local_count(self) -> int:

FILE: maggy/maggy/mesh/transport.py
  function derive_org_key (line 18) | def derive_org_key(org: str, secret: str) -> str:
  function compute_hmac (line 25) | def compute_hmac(payload: str, key: str) -> str:
  function verify_hmac (line 32) | def verify_hmac(
  function sign_message (line 40) | def sign_message(msg: MeshMessage, org_key: str) -> str:
  function verify_message (line 48) | def verify_message(

FILE: maggy/maggy/mesh/ws_client.py
  class MeshClient (line 17) | class MeshClient:
    method __init__ (line 20) | def __init__(self, peer_id: str) -> None:
    method connect (line 25) | async def connect(
    method send (line 49) | async def send(
    method broadcast (line 65) | async def broadcast(
    method close_all (line 75) | async def close_all(self) -> None:
    method connected_count (line 88) | def connected_count(self) -> int:
    method is_connected (line 91) | def is_connected(self, peer_id: str) -> bool:

FILE: maggy/maggy/mesh/ws_server.py
  function mesh_ws (line 24) | async def mesh_ws(websocket: WebSocket) -> None:
  function _handle_connection (line 41) | async def _handle_connection(websocket, manager) -> None:
  function _message_loop (line 65) | async def _message_loop(websocket, net) -> None:
  function _authenticate (line 83) | def _authenticate(
  function _dispatch (line 105) | async def _dispatch(msg: MeshMessage, net) -> None:

FILE: maggy/maggy/mnemos/fatigue.py
  class FatigueTracker (line 13) | class FatigueTracker:
    method __init__ (line 16) | def __init__(self, context_window: int = 200_000):
    method record (line 22) | def record(self, dimension: str, value: float) -> None:
    method on_model_switch (line 30) | def on_model_switch(self, new_context_window: int) -> None:
    method composite (line 35) | def composite(self) -> float:
    method state (line 38) | def state(self) -> str:

FILE: maggy/maggy/mnemos/signals.py
  class SignalLog (line 9) | class SignalLog:
    method __init__ (line 12) | def __init__(self, path: Path):
    method append (line 15) | def append(self, signal: dict) -> None:
    method recent (line 20) | def recent(self, n: int) -> list[dict]:

FILE: maggy/maggy/models/plan.py
  class PlanStep (line 9) | class PlanStep:
  class Plan (line 18) | class Plan:
    method step_count (line 28) | def step_count(self) -> int:
  class PlanDiff (line 33) | class PlanDiff:
    method conflict_count (line 42) | def conflict_count(self) -> int:
    method agreement_ratio (line 46) | def agreement_ratio(self) -> float:

FILE: maggy/maggy/observability/collector.py
  function _connect (line 23) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class ObservabilityCollector (line 33) | class ObservabilityCollector:
    method __init__ (line 34) | def __init__(self, db_path: Path):
    method record_signal (line 38) | def record_signal(
    method recent_signals (line 50) | def recent_signals(
    method _init_db (line 62) | def _init_db(self) -> None:

FILE: maggy/maggy/planning.py
  class PlanRequest (line 21) | class PlanRequest:
  class PlanningService (line 29) | class PlanningService:
    method __init__ (line 32) | def __init__(self, cfg: MaggyConfig):
    method should_dual_plan (line 35) | def should_dual_plan(self, blast_score: int) -> bool:
    method generate_plan (line 39) | def generate_plan(
    method diff_plans (line 65) | def diff_plans(
    method plan_task (line 97) | def plan_task(self, req: PlanRequest) -> dict:
  function _similar (line 121) | def _similar(a: str, b: str) -> bool:

FILE: maggy/maggy/process/discovery.py
  function discover_local (line 15) | def discover_local(project_path: Path) -> dict:
  function discover_github (line 67) | async def discover_github(

FILE: maggy/maggy/process/github_prs.py
  function _headers (line 21) | def _headers(token: str) -> dict[str, str]:
  function fetch_prs (line 29) | async def fetch_prs(
  function _fetch_pr_list (line 61) | async def _fetch_pr_list(
  function _fetch_pr_detail (line 97) | async def _fetch_pr_detail(
  function _parse_pr (line 111) | def _parse_pr(data: dict) -> PRRecord:
  function _pr_state (line 128) | def _pr_state(data: dict) -> str:
  function _fetch_reviews (line 134) | async def _fetch_reviews(
  function _fetch_checks (line 156) | async def _fetch_checks(
  function _fetch_files (line 178) | async def _fetch_files(
  function _log_error (line 197) | def _log_error(

FILE: maggy/maggy/process/model_router.py
  class RoutingDecision (line 56) | class RoutingDecision:
  function route_task (line 65) | def route_task(
  function _select_primary (line 107) | def _select_primary(
  function _select_validator (line 138) | def _select_validator(
  function _build_fallback (line 152) | def _build_fallback(
  function _build_reason (line 165) | def _build_reason(

FILE: maggy/maggy/process/models.py
  class ReviewRecord (line 9) | class ReviewRecord:
  class CheckRecord (line 19) | class CheckRecord:
  class PRRecord (line 29) | class PRRecord:
    method total_lines (line 48) | def total_lines(self) -> int:
    method review_rounds (line 52) | def review_rounds(self) -> int:
    method time_to_merge_hours (line 59) | def time_to_merge_hours(self) -> float | None:
    method ci_passed (line 74) | def ci_passed(self) -> bool:
  class ReviewSignal (line 84) | class ReviewSignal:
  class CISignal (line 94) | class CISignal:
    method failure_rate (line 103) | def failure_rate(self) -> float:
  class VelocitySignal (line 110) | class VelocitySignal:
  class ProcessReport (line 121) | class ProcessReport:
  class ModelTier (line 138) | class ModelTier:

FILE: maggy/maggy/process/patterns.py
  function identify_bottlenecks (line 19) | def identify_bottlenecks(
  function generate_preemptive_fixes (line 73) | def generate_preemptive_fixes(
  function generate_routing_recs (line 101) | def generate_routing_recs(
  function _avg_merge_time (line 170) | def _avg_merge_time(prs: list[PRRecord]) -> float | None:
  function _is_security_related (line 181) | def _is_security_related(pr: PRRecord) -> bool:
  function _is_test_only (line 189) | def _is_test_only(pr: PRRecord) -> bool:
  function _is_docs (line 198) | def _is_docs(pr: PRRecord) -> bool:

FILE: maggy/maggy/process/report.py
  function generate_summary (line 20) | def generate_summary(report: ProcessReport) -> str:
  function format_health_metrics (line 99) | def format_health_metrics(
  function _ci_pass_rate (line 145) | def _ci_pass_rate(

FILE: maggy/maggy/process/service.py
  class ProcessService (line 32) | class ProcessService:
    method __init__ (line 35) | def __init__(self, cfg: MaggyConfig):
    method analyze (line 43) | async def analyze(
    method get_report (line 105) | def get_report(self, project_key: str) -> dict | None:
    method get_health (line 109) | def get_health(self, project_key: str) -> dict | None:
    method _resolve_repo (line 116) | def _resolve_repo(

FILE: maggy/maggy/process/signals.py
  function extract_review_signals (line 57) | def extract_review_signals(
  function extract_ci_signals (line 95) | def extract_ci_signals(
  function extract_velocity_signals (line 139) | def extract_velocity_signals(
  function _matches_theme (line 175) | def _matches_theme(

FILE: maggy/maggy/process/store.py
  function _connect (line 20) | def _connect(path: Path) -> sqlite3.Connection:
  class ProcessStore (line 29) | class ProcessStore:
    method __init__ (line 32) | def __init__(self, db_path: Path):
    method _init_tables (line 37) | def _init_tables(self) -> None:
    method save_pr_data (line 64) | def save_pr_data(
    method load_pr_data (line 81) | def load_pr_data(
    method save_report (line 96) | def save_report(self, report: ProcessReport) -> None:
    method load_latest_report (line 155) | def load_latest_report(

FILE: maggy/maggy/providers/__init__.py
  function build (line 16) | def build(cfg) -> IssueTrackerProvider:

FILE: maggy/maggy/providers/asana.py
  class AsanaProvider (line 12) | class AsanaProvider:
    method __init__ (line 19) | def __init__(self, workspace_id: str, boards: dict[str, str], token: s...
    method provider_name (line 26) | def provider_name(self) -> str:
    method _headers (line 29) | def _headers(self) -> dict[str, str]:
    method _to_task (line 32) | def _to_task(self, t: dict) -> Task:
    method _get_my_gid (line 50) | async def _get_my_gid(self, client: httpx.AsyncClient) -> str:
    method list_tasks (line 58) | async def list_tasks(self, board: str | None = None, state: str = "ope...
    method get_task (line 97) | async def get_task(self, task_id: str) -> Task | None:
    method get_comments (line 107) | async def get_comments(self, task_id: str) -> list[Comment]:
    method add_comment (line 127) | async def add_comment(self, task_id: str, text: str) -> Comment | None:
    method update_status (line 144) | async def update_status(self, task_id: str, status: str) -> bool:
    method list_followed (line 154) | async def list_followed(self, user_id: str | None = None, limit: int =...
    method search_tasks (line 175) | async def search_tasks(self, query: str, limit: int = 20) -> list[Task]:

FILE: maggy/maggy/providers/base.py
  class Task (line 14) | class Task:
  class Comment (line 35) | class Comment:
  class IssueTrackerProvider (line 42) | class IssueTrackerProvider(Protocol):
    method list_tasks (line 45) | async def list_tasks(self, board: str | None = None, state: str = "ope...
    method get_task (line 49) | async def get_task(self, task_id: str) -> Task | None:
    method get_comments (line 52) | async def get_comments(self, task_id: str) -> list[Comment]:
    method add_comment (line 55) | async def add_comment(self, task_id: str, text: str) -> Comment | None:
    method update_status (line 58) | async def update_status(self, task_id: str, status: str) -> bool:
    method list_followed (line 62) | async def list_followed(self, user_id: str | None = None, limit: int =...
    method search_tasks (line 66) | async def search_tasks(self, query: str, limit: int = 20) -> list[Task]:
    method provider_name (line 69) | def provider_name(self) -> str:

FILE: maggy/maggy/providers/github_issues.py
  class GitHubIssuesProvider (line 16) | class GitHubIssuesProvider:
    method __init__ (line 24) | def __init__(self, org: str, repos: list[str], token: str, labels: lis...
    method provider_name (line 30) | def provider_name(self) -> str:
    method _headers (line 33) | def _headers(self) -> dict[str, str]:
    method _encode_id (line 40) | def _encode_id(self, repo: str, number: int) -> str:
    method _decode_id (line 45) | def _decode_id(self, task_id: str) -> tuple[str, int] | None:
    method _to_task (line 65) | def _to_task(self, repo: str, issue: dict) -> Task:
    method list_tasks (line 81) | async def list_tasks(self, board: str | None = None, state: str = "ope...
    method get_task (line 116) | async def get_task(self, task_id: str) -> Task | None:
    method get_comments (line 127) | async def get_comments(self, task_id: str) -> list[Comment]:
    method add_comment (line 146) | async def add_comment(self, task_id: str, text: str) -> Comment | None:
    method update_status (line 166) | async def update_status(self, task_id: str, status: str) -> bool:
    method list_followed (line 181) | async def list_followed(self, user_id: str | None = None, limit: int =...
    method search_tasks (line 218) | async def search_tasks(self, query: str, limit: int = 20) -> list[Task]:

FILE: maggy/maggy/providers/monday.py
  class MondayProvider (line 12) | class MondayProvider:
    method __init__ (line 15) | def __init__(self, api_token: str, board_id: str):
    method provider_name (line 19) | def provider_name(self) -> str:
    method _headers (line 22) | def _headers(self) -> dict[str, str]:
    method _to_task (line 28) | def _to_task(self, item: dict) -> Task:
    method _query (line 44) | async def _query(self, q: str) -> dict:
    method list_tasks (line 55) | async def list_tasks(self, board=None, state="open", limit=50) -> list...
    method get_task (line 65) | async def get_task(self, task_id: str) -> Task | None:
    method get_comments (line 73) | async def get_comments(self, task_id: str) -> list[Comment]:
    method add_comment (line 90) | async def add_comment(self, task_id: str, text: str) -> Comment | None:
    method update_status (line 102) | async def update_status(self, task_id: str, status: str) -> bool:
    method list_followed (line 105) | async def list_followed(self, user_id=None, limit=50) -> list[Task]:
    method search_tasks (line 108) | async def search_tasks(self, query: str, limit=20) -> list[Task]:
  function _col_value (line 112) | def _col_value(cols: list[dict], col_id: str) -> str:
  function _items_query (line 119) | def _items_query(board_id: str, limit: int) -> str:

FILE: maggy/maggy/recovery/rollback.py
  function _validate_session_id (line 11) | def _validate_session_id(session_id: str) -> None:
  class RollbackManager (line 16) | class RollbackManager:
    method create_savepoint (line 17) | async def create_savepoint(self, session_id: str, working_dir: str) ->...
    method rollback (line 25) | async def rollback(self, session_id: str, working_dir: str) -> bool:
    method list_savepoints (line 30) | async def list_savepoints(self, working_dir: str) -> list[str]:
    method delete_savepoint (line 36) | async def delete_savepoint(self, session_id: str, working_dir: str) ->...
  function _run_git (line 41) | async def _run_git(working_dir: str, *args: str) -> tuple[int, str]:
  function _tag_name (line 54) | def _tag_name(session_id: str) -> str:

FILE: maggy/maggy/registry.py
  class ProjectRegistry (line 8) | class ProjectRegistry:
    method __init__ (line 11) | def __init__(self, cfg: MaggyConfig):
    method list (line 14) | def list(self) -> list[ProjectConfig]:
    method get (line 17) | def get(self, name: str) -> ProjectConfig | None:
    method add (line 20) | def add(self, project: ProjectConfig) -> None:
    method remove (line 25) | def remove(self, name: str) -> bool:

FILE: maggy/maggy/routing.py
  class RoutingContext (line 29) | class RoutingContext:
  class RoutingService (line 40) | class RoutingService:
    method __init__ (line 43) | def __init__(self, cfg: MaggyConfig):
    method route (line 52) | def route(self, ctx: RoutingContext) -> RoutingDecision:
    method record_outcome (line 82) | def record_outcome(
    method reload_rules (line 96) | def reload_rules(self) -> None:
    method get_heatmap (line 100) | def get_heatmap(self) -> list[dict]:
    method _blast_tier (line 104) | def _blast_tier(self, score: int) -> str:
    method _is_calibrated (line 111) | def _is_calibrated(self, model: str) -> bool:
    method _forced_decision (line 115) | def _forced_decision(
    method _penalize_uncalibrated (line 139) | def _penalize_uncalibrated(
  function _find_tier (line 154) | def _find_tier(name: str):

FILE: maggy/maggy/routing_rules.py
  class ModelOverride (line 18) | class ModelOverride:
  class PerformanceRecord (line 28) | class PerformanceRecord:
  class Convention (line 38) | class Convention:
  class StakesLevel (line 47) | class StakesLevel:
  class StakesPatterns (line 56) | class StakesPatterns:
  class CascadePolicy (line 65) | class CascadePolicy:
  class RoutingRules (line 76) | class RoutingRules:
  function _now_iso (line 98) | def _now_iso() -> str:
  function apply_override (line 102) | def apply_override(
  function record_outcome (line 118) | def record_outcome(
  function learn_override (line 135) | def learn_override(
  function conventions_for (line 152) | def conventions_for(
  function _trusted (line 169) | def _trusted(override: ModelOverride) -> bool:
  function _update_perf (line 173) | def _update_perf(

FILE: maggy/maggy/routing_rules_defaults.py
  function default_conventions (line 53) | def default_conventions() -> list[Convention]:
  function default_stakes (line 58) | def default_stakes() -> StakesPatterns:
  function default_rules (line 74) | def default_rules() -> RoutingRules:

FILE: maggy/maggy/routing_rules_io.py
  function save (line 25) | def save(rules: RoutingRules, path: Path | None = None) -> None:
  function load (line 33) | def load(path: Path | None = None) -> RoutingRules:
  function to_dict (line 49) | def to_dict(rules: RoutingRules) -> dict:
  function from_yaml (line 79) | def from_yaml(path: Path) -> RoutingRules:
  function _stakes_to_dict (line 124) | def _stakes_to_dict(stakes: StakesPatterns) -> dict:
  function _level_to_dict (line 132) | def _level_to_dict(level: StakesLevel) -> dict:
  function _cascade_to_dict (line 140) | def _cascade_to_dict(cascade: CascadePolicy) -> dict:
  function _override_to_dict (line 150) | def _override_to_dict(v: ModelOverride) -> dict:
  function _perf_to_dict (line 157) | def _perf_to_dict(v: PerformanceRecord) -> dict:
  function _stakes_from_dict (line 165) | def _stakes_from_dict(raw: dict) -> StakesPatterns:

FILE: maggy/maggy/scores.py
  function _connect (line 34) | def _connect(path: Path) -> Iterator[sqlite3.Connection]:
  class RewardTable (line 46) | class RewardTable:
    method __init__ (line 49) | def __init__(self, cfg: MaggyConfig):
    method _init_db (line 54) | def _init_db(self) -> None:
    method record (line 58) | def record(
    method best_model (line 74) | def best_model(
    method heatmap (line 112) | def heatmap(self) -> list[dict]:

FILE: maggy/maggy/services/account_guide.py
  class AccountProfile (line 19) | class AccountProfile:
  function detect_accounts (line 28) | def detect_accounts(home: Path | None = None) -> list[AccountProfile]:
  function suggest_switch (line 43) | def suggest_switch(provider: str) -> str:
  function render_switch_guide (line 60) | def render_switch_guide(provider: str) -> None:

FILE: maggy/maggy/services/activity.py
  class ActiveSession (line 17) | class ActiveSession:
  class RecentPrompt (line 32) | class RecentPrompt:
  class ActivityService (line 42) | class ActivityService:
    method get_activity (line 45) | def get_activity(self) -> dict:
  function _scan_processes (line 57) | def _scan_processes() -> list[ActiveSession]:
  function _parse_claude_processes (line 72) | def _parse_claude_processes(
  function _is_cli_process (line 98) | def _is_cli_process(line: str) -> bool:
  function _extract_pid (line 112) | def _extract_pid(line: str) -> int:
  function _extract_flag (line 123) | def _extract_flag(line: str, flag: str) -> str:
  function _get_cwd (line 134) | def _get_cwd(pid: int) -> str:
  function _recent_prompts (line 154) | def _recent_prompts(
  function _read_claude_history (line 175) | def _read_claude_history(
  function _read_codex_history (line 205) | def _read_codex_history(
  function _read_kimi_history (line 234) | def _read_kimi_history(
  function _tail_lines (line 271) | def _tail_lines(path: Path, n: int) -> list[str]:
  function _ms_to_iso (line 280) | def _ms_to_iso(ms: int | float) -> str:
  function _s_to_iso (line 293) | def _s_to_iso(s: int | float) -> str:

FILE: maggy/maggy/services/ai_client.py
  function ai_complete (line 12) | async def ai_complete(
  function _api_complete (line 28) | async def _api_complete(
  function _cli_complete (line 46) | async def _cli_complete(

FILE: maggy/maggy/services/cascade.py
  class CascadeAttempt (line 20) | class CascadeAttempt:
  class CascadeResult (line 31) | class CascadeResult:
  function cascade_execute (line 41) | async def cascade_execute(

FILE: maggy/maggy/services/chat.py
  class ChatMessage (line 23) | class ChatMessage:
  class ChatSession (line 36) | class ChatSession:
  function enqueue_msg (line 57) | def enqueue_msg(session: ChatSession, message: str) -> int:
  class ChatManager (line 65) | class ChatManager:
    method __init__ (line 68) | def __init__(self, cfg: MaggyConfig):
    method create_session (line 73) | def create_session(
    method find_by_project (line 93) | def find_by_project(self, key: str) -> ChatSession | None:
    method auto_connect (line 100) | def auto_connect(
    method get_session (line 123) | def get_session(self, sid: str) -> ChatSession | None:
    method list_sessions (line 126) | def list_sessions(self) -> list[ChatSession]:
    method delete_session (line 129) | def delete_session(self, session_id: str) -> bool:
    method send (line 136) | async def send(
    method _drain_queue (line 159) | async def _drain_queue(
    method _validate_path (line 172) | def _validate_path(self, path: str) -> str:
    method _resolve_project (line 190) | def _resolve_project(self, project_key: str) -> str:

FILE: maggy/maggy/services/chat_context.py
  function build_project_context (line 18) | def build_project_context(
  function _match_history (line 33) | def _match_history(
  function _match_from_report (line 47) | def _match_from_report(
  function _path_candidates (line 85) | def _path_candidates(
  function _format_recent_prompts (line 100) | def _format_recent_prompts(
  function resolve_claude_session_id (line 118) | def resolve_claude_session_id(

FILE: maggy/maggy/services/chat_router.py
  function estimate_blast (line 66) | def estimate_blast(message: str) -> int:
  function _keyword_score (line 81) | def _keyword_score(high: int, mid: int, low: int) -> int:
  function _apply_intent (line 98) | def _apply_intent(message: str, score: int) -> int:
  function estimate_type (line 107) | def estimate_type(message: str) -> str:
  class RouteDecision (line 121) | class RouteDecision:
  class RoutedChat (line 130) | class RoutedChat:
    method __init__ (line 133) | def __init__(self, routing, budget):
    method decide (line 137) | def decide(
    method _model_name (line 158) | def _model_name(self, primary) -> str:

FILE: maggy/maggy/services/chat_stream.py
  function build_cmd (line 24) | def build_cmd(session: ChatSession, message: str) -> list[str]:
  function parse_chunk (line 37) | def parse_chunk(
  function _extract_assistant (line 64) | def _extract_assistant(data: dict) -> dict:
  function check_context_pressure (line 77) | def check_context_pressure(session: ChatSession) -> dict | None:
  function stream_message (line 87) | async def stream_message(

FILE: maggy/maggy/services/checkpoint.py
  class Checkpoint (line 15) | class Checkpoint:
    method serialize (line 26) | def serialize(self) -> str:
    method deserialize (line 35) | def deserialize(cls, data: str) -> Checkpoint:
    method to_prompt (line 40) | def to_prompt(self) -> str:
  function create_checkpoint (line 69) | def create_checkpoint(

FILE: maggy/maggy/services/competitor.py
  function _connect_sqlite (line 29) | def _connect_sqlite(path: Path) -> sqlite3.Connection:
  function _parse_feed_date (line 42) | def _parse_feed_date(raw: str) -> datetime | None:
  function _is_safe_feed_url (line 70) | def _is_safe_feed_url(url: str) -> bool:
  class CompetitorService (line 110) | class CompetitorService:
    method __init__ (line 111) | def __init__(self, cfg: MaggyConfig):
    method _init_db (line 117) | def _init_db(self) -> None:
    method load_registry (line 149) | def load_registry(self) -> dict[str, dict]:
    method save_registry (line 157) | def save_registry(self, registry: dict[str, dict]) -> None:
    method discover (line 163) | async def discover(self) -> dict:
    method list_all (line 231) | def list_all(self) -> list[dict]:
    method monitor_all (line 236) | async def monitor_all(self) -> dict:
    method _get_cursor (line 252) | def _get_cursor(self, key: str) -> str:
    method _set_cursor (line 257) | def _set_cursor(self, key: str, cursor: str) -> None:
    method _classify (line 265) | def _classify(self, title: str) -> str:
    method _log_event (line 279) | def _log_event(self, competitor_id: str, competitor_name: str, event_t...
    method _check_rss (line 293) | async def _check_rss(self, cid: str, comp: dict) -> int:
    method _check_google_news (line 335) | async def _check_google_news(self, cid: str, comp: dict) -> int:
    method get_news (line 376) | def get_news(self, limit: int = 100) -> list[dict]:
    method get_daily_briefing (line 387) | async def get_daily_briefing(self, refresh: bool = False) -> dict:

FILE: maggy/maggy/services/context_compactor.py
  class CompactionResult (line 23) | class CompactionResult:
  function estimate_tokens (line 29) | def estimate_tokens(messages: list[dict]) -> int:
  function should_compact (line 35) | def should_compact(messages: list[dict], context_window: int) -> bool:
  function compact (line 41) | async def compact(
  function _format_for_summary (line 69) | def _format_for_summary(messages: list[dict]) -> str:

FILE: maggy/maggy/services/convention_inferrer.py
  function collect_fingerprint (line 50) | def collect_fingerprint(working_dir: str) -> str:
  function parse_conventions (line 57) | def parse_conventions(text: str) -> list[Convention]:
  function infer_conventions (line 71) | async def infer_conventions(
  function ensure_inferred (line 87) | async def ensure_inferred(
  function _file_tree (line 109) | def _file_tree(root: Path) -> str:
  function _config_snippets (line 127) | def _config_snippets(root: Path) -> str:
  function _git_log (line 141) | def _git_log(root: Path) -> str:

FILE: maggy/maggy/services/convention_scanner.py
  class ScanRule (line 20) | class ScanRule:
  function scan_project (line 90) | def scan_project(working_dir: str) -> list[Convention]:
  function ensure_scanned (line 107) | def ensure_scanned(
  function _matches (line 117) | def _matches(root: Path, rule: ScanRule) -> bool:

FILE: maggy/maggy/services/executor.py
  class ExecutorService (line 28) | class ExecutorService:
    method __init__ (line 29) | def __init__(self, cfg: MaggyConfig, provider: IssueTrackerProvider, s...
    method start (line 44) | async def start(self, task_id: str, mode: str = "tdd",
    method get_session (line 64) | def get_session(self, sid: str) -> dict | None: return self._sessions....
    method list_sessions (line 65) | def list_sessions(self) -> list[dict]: return list(self._sessions.valu...
    method _run (line 66) | async def _run(self, ctx: SessionCtx, mode: str) -> None:
    method _run_plan (line 82) | async def _run_plan(self, ctx: SessionCtx) -> None:
    method _run_tdd (line 91) | async def _run_tdd(self, ctx: SessionCtx) -> None:
    method _reviewed_step (line 117) | async def _reviewed_step(self, ctx: SessionCtx, step: StepSpec) -> tup...
    method _run_step (line 129) | async def _run_step(self, ctx: SessionCtx, step: StepSpec) -> tuple[bo...
    method _review_step (line 137) | async def _review_step(self, ctx: SessionCtx, step: StepSpec, output: ...
    method _run_model (line 143) | async def _run_model(self, ctx: SessionCtx, prompt: str, turns: int) -...
    method _send (line 159) | async def _send(self, decision, name, prompt, ctx):
    method _emit_status (line 172) | def _emit_status(self, agent: str, status: str) -> None:
    method _verify_red (line 175) | async def _verify_red(self, ctx: SessionCtx) -> bool:
    method _verify_green (line 184) | async def _verify_green(self, ctx: SessionCtx) -> bool:
    method _dual_plan (line 195) | async def _dual_plan(self, ctx: SessionCtx) -> None:

FILE: maggy/maggy/services/executor_helpers.py
  function route_model (line 25) | def route_model(task: Task, routing: RoutingService) -> RoutingDecision:
  function blast_score (line 43) | def blast_score(task: Task) -> int:
  function int_value (line 49) | def int_value(value: object) -> int:
  function model_name (line 57) | def model_name(primary: object) -> str:
  function track_fatigue (line 64) | def track_fatigue(fatigue: FatigueTracker, result: RunResult) -> None:
  function log_signal (line 70) | def log_signal(signals: SignalLog, sid: str, label: str, result: RunResu...
  function write_checkpoint (line 78) | def write_checkpoint(
  function save_rollback (line 89) | async def save_rollback(
  function try_rollback (line 99) | async def try_rollback(
  function maybe_escalate (line 109) | def maybe_escalate(
  function build_icpg_context (line 122) | async def build_icpg_context(cfg: "MaggyConfig", task: Task) -> str:
  function resolve_working_dir (line 149) | def resolve_working_dir(cfg: "MaggyConfig", requested: str | None, task:...
  function pick_working_dir (line 167) | def pick_working_dir(cfg: "MaggyConfig", task: "Task") -> str:
  function post_plan (line 186) | async def post_plan(provider, task_id: str, output: str) -> None:
  function _task_type (line 196) | def _task_type(task: "Task") -> str:
  function _security_flag (line 200) | def _security_flag(raw: dict, task_type: str) -> bool:

FILE: maggy/maggy/services/executor_prompts.py
  function plan_prompt (line 24) | def plan_prompt(task: Task, icpg_ctx: str, routing: RoutingService) -> str:
  function analysis_prompt (line 35) | def analysis_prompt(task: Task, icpg_ctx: str, routing: RoutingService) ...
  function tests_prompt (line 46) | def tests_prompt(
  function impl_prompt (line 61) | def impl_prompt(task: Task, icpg_ctx: str, routing: RoutingService) -> str:
  function extract_keywords (line 73) | def extract_keywords(text: str) -> list[str]:
  function _icpg_block (line 86) | def _icpg_block(icpg_ctx: str) -> str:
  function _task_type (line 92) | def _task_type(task: Task) -> str:
  function _conventions_block (line 98) | def _conventions_block(task: Task, routing: RoutingService) -> str:

FILE: maggy/maggy/services/executor_types.py
  class SessionCtx (line 13) | class SessionCtx:
  class StepSpec (line 23) | class StepSpec:

FILE: maggy/maggy/services/inbox.py
  function _connect_sqlite (line 23) | def _connect_sqlite(path: Path) -> sqlite3.Connection:
  class InboxService (line 38) | class InboxService:
    method __init__ (line 39) | def __init__(self, cfg: MaggyConfig, provider: IssueTrackerProvider):
    method _init_db (line 46) | def _init_db(self) -> None:
    method _read_cache (line 56) | def _read_cache(self, ignore_ttl: bool = False) -> list[dict] | None:
    method _write_cache (line 70) | def _write_cache(self, items: list[dict]) -> None:
    method get_prioritized (line 78) | async def get_prioritized(self, force_refresh: bool = False) -> list[d...
    method _rank_with_ai (line 106) | async def _rank_with_ai(self, tasks: list[Task]) -> list[dict]:
    method _build_rank_prompt (line 149) | def _build_rank_prompt(self, tasks: list[Task]) -> str:
    method _call_ai (line 173) | async def _call_ai(self, prompt: str) -> str | None:
    method _task_to_dict (line 177) | def _task_to_dict(self, t: Task, rank: int, reason: str) -> dict:

FILE: maggy/maggy/services/monitor.py
  class MonitorConfig (line 20) | class MonitorConfig:
  class MonitorEvent (line 31) | class MonitorEvent:
  class MonitorService (line 42) | class MonitorService:
    method __init__ (line 45) | def __init__(self, db_path: Path) -> None:
    method _init_tables (line 49) | def _init_tables(self) -> None:
    method add (line 66) | def add(self, cfg: MonitorConfig) -> None:
    method remove (line 74) | def remove(self, project_key: str) -> None:
    method list_active (line 81) | def list_active(self) -> list[MonitorConfig]:
    method is_new (line 87) | def is_new(self, event_id: str, project_key: str) -> bool:
    method mark_seen (line 94) | def mark_seen(self, event_id: str, project_key: str) -> None:
    method status (line 102) | def status(self) -> dict:
    method poll (line 109) | async def poll(self, cfg: MonitorConfig) -> list[MonitorEvent]:
  function _row_to_config (line 118) | def _row_to_config(row: tuple) -> MonitorConfig:
  function _poll_github (line 126) | async def _poll_github(svc: MonitorService, cfg: MonitorConfig) -> list[...
  function _poll_monday (line 149) | async def _poll_monday(svc: MonitorService, cfg: MonitorConfig) -> list[...

FILE: maggy/maggy/services/output_reviewer.py
  class ReviewResult (line 28) | class ReviewResult:
  function _parse_review (line 33) | def _parse_review(text: str) -> ReviewResult:
  function _build_prompt (line 44) | def _build_prompt(step_label: str, output: str) -> str:
  function review_output (line 56) | async def review_output(

FILE: maggy/maggy/services/planner.py
  class PlanResult (line 11) | class PlanResult:
  class DualPlanner (line 17) | class DualPlanner:
    method __init__ (line 18) | def __init__(self, pi: PiAdapter):
    method plan (line 21) | async def plan(
    method counter_check (line 27) | async def counter_check(self, plan_text: str, wd: str) -> str:
    method dual_plan (line 31) | async def dual_plan(
    method _send (line 38) | async def _send(self, model: str, prompt: str, wd: str) -> str:
  function _plan_prompt (line 43) | def _plan_prompt(task_title: str, task_desc: str) -> str:
  function _review_prompt (line 52) | def _review_prompt(plan_text: str) -> str:
  function _result_text (line 61) | def _result_text(result: RunResult, model: str) -> str:
  function _conflicts (line 68) | def _conflicts(text: str) -> list[str]:

FILE: maggy/maggy/services/session_detect.py
  function _home (line 17) | def _home() -> Path:
  class CliSessionInfo (line 23) | class CliSessionInfo:
  class DetectedSessions (line 32) | class DetectedSessions:
  function detect_all (line 40) | def detect_all(working_dir: str) -> DetectedSessions:
  function detect_claude (line 53) | def detect_claude(working_dir: str) -> CliSessionInfo | None:
  function detect_kimi (line 70) | def detect_kimi(working_dir: str) -> CliSessionInfo | None:
  function detect_codex (line 87) | def detect_codex(working_dir: str) -> CliSessionInfo | None:
  function _parse_json (line 108) | def _parse_json(text: str) -> dict | None:
  function _read_first_line (line 119) | def _read_first_line(path: Path) -> str:

FILE: maggy/maggy/services/stakes.py
  class StakesResult (line 15) | class StakesResult:
  function classify_stakes (line 22) | def classify_stakes(
  function _matches (line 43) | def _matches(

FILE: maggy/maggy/services/tdd_verifier.py
  class VerifyResult (line 17) | class VerifyResult:
  function verify_tests_exist (line 26) | async def verify_tests_exist(wd: str) -> VerifyResult:
  function verify_tests_fail (line 37) | async def verify_tests_fail(wd: str) -> VerifyResult:
  function verify_tests_pass (line 52) | async def verify_tests_pass(wd: str) -> VerifyResult:
  function verify_lint (line 64) | async def verify_lint(wd: str) -> VerifyResult:
  function verify_coverage (line 74) | async def verify_coverage(
  function _run_cmd (line 89) | async def _run_cmd(
  function _count_collected (line 111) | def _count_collected(output: str) -> int:
  function _count_failures (line 117) | def _count_failures(output: str) -> int:
  function _parse_coverage (line 123) | def _parse_coverage(output: str) -> float:

FILE: maggy/maggy/services/vision.py
  function _validate (line 26) | def _validate(path: str) -> Path | None:
  function _encode (line 36) | def _encode(path: Path) -> str:
  function analyze_image (line 41) | def analyze_image(
  function _err (line 86) | def _err(msg: str) -> dict:

FILE: maggy/maggy/static/app.js
  constant API (line 4) | const API = '/api';
  constant CURRENT_TAB (line 5) | let CURRENT_TAB = 'chat';
  function api (line 8) | async function api(path, opts = {}) {
  function esc (line 21) | function esc(s) {
  function safeHref (line 30) | function safeHref(url) {
  function jsStr (line 45) | function jsStr(s) {
  function relDate (line 55) | function relDate(iso) {
  function switchTab (line 67) | function switchTab(tab) {
  function toggleSystemMenu (line 102) | function toggleSystemMenu() {
  function openDrawer (line 118) | function openDrawer(title, html) {
  function closeDrawer (line 123) | function closeDrawer() {
  function loadInbox (line 128) | async function loadInbox(refresh = false) {
  function loadFollowed (line 204) | async function loadFollowed() {
  function openTaskDetail (line 233) | async function openTaskDetail(taskId) {
  function postReply (line 280) | async function postReply(taskId) {
  function executeTask (line 291) | async function executeTask(taskId, mode) {
  constant COMP_VIEW (line 302) | let COMP_VIEW = 'news';
  function loadCompetitors (line 304) | async function loadCompetitors() {
  function renderNewsFeed (line 344) | function renderNewsFeed(news) {
  function loadBriefing (line 375) | async function loadBriefing() {
  function regenerateBriefing (line 390) | async function regenerateBriefing() {
  function discoverCompetitors (line 401) | async function discoverCompetitors() {
  function scanCompetitors (line 412) | async function scanCompetitors() {
  constant CHAT_SESSION_ID (line 423) | let CHAT_SESSION_ID = null;
  constant CHAT_SESSIONS_CACHE (line 424) | let CHAT_SESSIONS_CACHE = [];
  function loadChat (line 426) | async function loadChat() {
  function renderChatUI (line 441) | function renderChatUI(pane) {
  function renderChatSidebar (line 451) | function renderChatSidebar(sessions) {
  function renderChatMain (line 473) | function renderChatMain() {
  function newChatSession (line 496) | async function newChatSession() {
  function openChatSession (line 525) | function openChatSession(id) {
  function loadChatMessages (line 531) | async function loadChatMessages(id) {
  function renderSessionHeader (line 550) | function renderSessionHeader(data) {
  function renderHistoryContext (line 554) | function renderHistoryContext(ctx) {
  function renderUserMsg (line 561) | function renderUserMsg(m) {
  function renderAssistantMsg (line 568) | function renderAssistantMsg(m) {
  function sendChatMessage (line 575) | async function sendChatMessage() {
  function streamChatResponse (line 598) | async function streamChatResponse(message, el) {
  function loadSettings (line 627) | async function loadSettings() {
  function loadBudget (line 652) | async function loadBudget() {
  function loadRouting (line 691) | async function loadRouting() {
  function loadProcess (line 717) | async function loadProcess() {
  function renderPIStats (line 740) | function renderPIStats(events, history, landscape) {
  function renderPIPatterns (line 749) | function renderPIPatterns(history) {
  function renderPIHealth (line 758) | function renderPIHealth(improve) {
  function renderPIActivity (line 783) | function renderPIActivity(activity) {
  function renderPIActions (line 809) | function renderPIActions() {
  function triggerAnalysis (line 820) | async function triggerAnalysis(type) {
  function showToast (line 839) | function showToast(msg) {
  function loadForge (line 848) | async function loadForge() {
  function checkSetup (line 886) | async function checkSetup() {
  function showSetupWizard (line 895) | function showSetupWizard(status) {
  function enterLocalMode (line 960) | function enterLocalMode() {
  function reloadConfig (line 978) | async function reloadConfig() {
  function autoConfigureSetup (line 992) | async function autoConfigureSetup() {
  function loadAll (line 1012) | async function loadAll() {

FILE: maggy/tests/conftest.py
  function tmp_dir (line 23) | def tmp_dir(tmp_path: Path) -> Path:
  function mock_cfg (line 28) | def mock_cfg(tmp_path: Path) -> MaggyConfig:

FILE: maggy/tests/integration/test_full_task_flow.py
  class TestFullTaskFlow (line 22) | class TestFullTaskFlow:
    method test_route_emit_reward (line 23) | def test_route_emit_reward(self, mock_cfg, tmp_path: Path):
    method test_multi_task_routing (line 70) | def test_multi_task_routing(self, mock_cfg):

FILE: maggy/tests/integration/test_model_fallback.py
  class TestModelFallback (line 12) | class TestModelFallback:
    method test_fatigue_triggers_checkpoint (line 13) | def test_fatigue_triggers_checkpoint(self):
    method test_cross_model_checkpoint_round_trip (line 41) | def test_cross_model_checkpoint_round_trip(self):
    method test_fresh_model_low_fatigue (line 59) | def test_fresh_model_low_fatigue(self):

FILE: maggy/tests/integration/test_process_loop.py
  class TestProcessLoop (line 20) | class TestProcessLoop:
    method test_cikg_gap_to_engram (line 21) | def test_cikg_gap_to_engram(self, tmp_path: Path):
    method test_lexon_to_engram (line 55) | def test_lexon_to_engram(self, tmp_path: Path):
    method test_full_diagnostics (line 78) | def test_full_diagnostics(self, tmp_path: Path):

FILE: maggy/tests/test_account_guide.py
  function test_account_profile_dataclass (line 12) | def test_account_profile_dataclass():
  function test_detect_accounts_finds_claude (line 22) | def test_detect_accounts_finds_claude(tmp_path):
  function test_detect_accounts_finds_codex (line 31) | def test_detect_accounts_finds_codex(tmp_path):
  function test_suggest_switch_anthropic (line 39) | def test_suggest_switch_anthropic():
  function test_suggest_switch_openai (line 46) | def test_suggest_switch_openai():

FILE: maggy/tests/test_activity.py
  class TestParseClaudeProcesses (line 20) | class TestParseClaudeProcesses:
    method test_detects_running_session (line 21) | def test_detects_running_session(self):
    method test_detects_agent_subprocess (line 36) | def test_detects_agent_subprocess(self):
    method test_ignores_non_cli_processes (line 55) | def test_ignores_non_cli_processes(self):
    method test_empty_input (line 63) | def test_empty_input(self):
  class TestRecentPrompts (line 67) | class TestRecentPrompts:
    method test_reads_claude_history (line 68) | def test_reads_claude_history(self, tmp_path: Path):
    method test_reads_codex_history (line 86) | def test_reads_codex_history(self, tmp_path: Path):
    method test_merges_and_sorts_by_time (line 102) | def test_merges_and_sorts_by_time(self, tmp_path: Path):
    method test_limits_output (line 120) | def test_limits_output(self, tmp_path: Path):
    method test_no_history_files (line 135) | def test_no_history_files(self, tmp_path: Path):
    method test_malformed_json_skipped (line 142) | def test_malformed_json_skipped(self, tmp_path: Path):
  class TestActivityService (line 157) | class TestActivityService:
    method test_get_activity_shape (line 158) | def test_get_activity_shape(self):
    method test_serializes_sessions (line 171) | def test_serializes_sessions(self):
    method test_serializes_prompts (line 193) | def test_serializes_prompts(self):

FILE: maggy/tests/test_api_endpoints.py
  function app_with_services (line 46) | def app_with_services(tmp_path: Path) -> FastAPI:
  function client (line 131) | def client(app_with_services: FastAPI) -> TestClient:
  class TestBudgetAPI (line 138) | class TestBudgetAPI:
    method test_get_budget_empty (line 139) | def test_get_budget_empty(self, client: TestClient):
    method test_budget_by_provider_empty (line 147) | def test_budget_by_provider_empty(self, client: TestClient):
    method test_budget_with_spend (line 152) | def test_budget_with_spend(
  class TestRoutingAPI (line 176) | class TestRoutingAPI:
    method test_heatmap_empty (line 177) | def test_heatmap_empty(self, client: TestClient):
    method test_decide_low_blast (line 182) | def test_decide_low_blast(self, client: TestClient):
    method test_decide_high_blast (line 191) | def test_decide_high_blast(self, client: TestClient):
    method test_heatmap_after_recording (line 198) | def test_heatmap_after_recording(
  class TestUsersAPI (line 208) | class TestUsersAPI:
    method test_create_user (line 209) | def test_create_user(self, client: TestClient):
  class TestEventsAPI (line 224) | class TestEventsAPI:
    method test_events_empty (line 225) | def test_events_empty(self, client: TestClient):
    method test_event_count_empty (line 230) | def test_event_count_empty(self, client: TestClient):
    method test_trace_empty (line 235) | def test_trace_empty(self, client: TestClient):
    method test_events_after_emit (line 240) | def test_events_after_emit(
  class TestCIKGAPI (line 265) | class TestCIKGAPI:
    method test_landscape_empty (line 266) | def test_landscape_empty(self, client: TestClient):
    method test_gaps_no_feature (line 272) | def test_gaps_no_feature(self, client: TestClient):
    method test_landscape_with_data (line 278) | def test_landscape_with_data(
  class TestPlanningAPI (line 304) | class TestPlanningAPI:
    method test_single_plan (line 305) | def test_single_plan(self, client: TestClient):
    method test_dual_plan (line 315) | def test_dual_plan(self, client: TestClient):
  class TestDeployAPI (line 328) | class TestDeployAPI:
    method test_sessions_empty (line 329) | def test_sessions_empty(self, client: TestClient):
    method test_create_and_get (line 334) | def test_create_and_get(self, client: TestClient):
    method test_missing_session (line 347) | def test_missing_session(self, client: TestClient):
  class TestForgeAPI (line 356) | class TestForgeAPI:
    method test_forge_status (line 357) | def test_forge_status(self, client: TestClient):
    method test_forge_search (line 364) | def test_forge_search(self, client: TestClient):
    method test_forge_gaps_empty (line 369) | def test_forge_gaps_empty(self, client: TestClient):
    method test_report_gap (line 374) | def test_report_gap(self, client: TestClient):
  class TestEngramAPI (line 391) | class TestEngramAPI:
    method test_query_empty (line 392) | def test_query_empty(self, client: TestClient):
    method test_diagnostics_empty (line 397) | def test_diagnostics_empty(self, client: TestClient):
    method test_query_with_data (line 403) | def test_query_with_data(
    method test_diagnostics_with_data (line 421) | def test_diagnostics_with_data(
  class TestLexonAPI (line 441) | class TestLexonAPI:
    method test_parse_known (line 442) | def test_parse_known(self, client: TestClient):
    method test_parse_unknown (line 449) | def test_parse_unknown(self, client: TestClient):
    method test_learn (line 456) | def test_learn(self, client: TestClient):
  class TestMeshAPI (line 472) | class TestMeshAPI:
    method test_mesh_status_enabled (line 473) | def test_mesh_status_enabled(self, client: TestClient):
    method test_mesh_peers_empty (line 481) | def test_mesh_peers_empty(self, client: TestClient):
    method test_mesh_networks (line 486) | def test_mesh_networks(self, client: TestClient):
    method test_mesh_quarantine_requires_org (line 493) | def test_mesh_quarantine_requires_org(
    method test_mesh_quarantine_with_org (line 500) | def test_mesh_quarantine_with_org(
    method test_mesh_add_peer (line 507) | def test_mesh_add_peer(self, client: TestClient):
  class TestUnconfiguredState (line 525) | class TestUnconfiguredState:
    method unconfigured_client (line 529) | def unconfigured_client(self) -> TestClient:
    method test_budget_unconfigured (line 559) | def test_budget_unconfigured(
    method test_routing_unconfigured (line 566) | def test_routing_unconfigured(
    method test_events_unconfigured (line 573) | def test_events_unconfigured(
    method test_mesh_unconfigured (line 579) | def test_mesh_unconfigured(
    method test_engram_unconfigured (line 586) | def test_engram_unconfigured(
    method test_lexon_unconfigured (line 592) | def test_lexon_unconfigured(
    method test_deploy_unconfigured (line 598) | def test_deploy_unconfigured(
    method test_forge_unconfigured (line 604) | def test_forge_unconfigured(
    method test_planning_unconfigured (line 610) | def test_planning_unconfigured(
    method test_cikg_unconfigured (line 619) | def test_cikg_unconfigured(
  class TestHistoryEndpoints (line 629) | class TestHistoryEndpoints:
    method test_providers (line 632) | def test_providers(self, client: TestClient):
    method test_analyze (line 637) | def test_analyze(self, client: TestClient):
    method test_report_empty (line 644) | def test_report_empty(self, client: TestClient):
    method test_sessions (line 648) | def test_sessions(self, client: TestClient):
    method test_sessions_filter (line 655) | def test_sessions_filter(self, client: TestClient):
  class TestDiscoveryEndpoint (line 665) | class TestDiscoveryEndpoint:
    method test_discovery_returns_data (line 666) | def test_discovery_returns_data(
    method test_health_has_mode (line 676) | def test_health_has_mode(
  class TestHeartbeatEndpoints (line 689) | class TestHeartbeatEndpoints:
    method test_status_no_scheduler (line 690) | def test_status_no_scheduler(self, client: TestClient):
    method test_trigger_no_scheduler (line 695) | def test_trigger_no_scheduler(self, client: TestClient):
    method test_status_with_scheduler (line 699) | def test_status_with_scheduler(
  class TestImproveEndpoints (line 718) | class TestImproveEndpoints:
    method test_report_empty (line 719) | def test_report_empty(self, client: TestClient):
    method test_analyze_returns_report (line 724) | def test_analyze_returns_report(
    method test_report_after_analyze (line 735) | def test_report_after_analyze(

FILE: maggy/tests/test_benchmark_scenario.py
  function _cfg (line 48) | def _cfg(tmp_path) -> MaggyConfig:
  class TestRoutingAccuracy (line 93) | class TestRoutingAccuracy:
    method test_all_10_tasks_route_correctly (line 96) | def test_all_10_tasks_route_correctly(self, tmp_path):
    method test_routing_accuracy_score (line 130) | def test_routing_accuracy_score(self, tmp_path):
  class TestBudgetEfficiency (line 167) | class TestBudgetEfficiency:
    method test_spend_distribution (line 168) | def test_spend_distribution(self, tmp_path):
  class TestFallbackResilience (line 198) | class TestFallbackResilience:
    method test_quota_recovery (line 200) | async def test_quota_recovery(self):
    method test_full_chain_failure (line 219) | async def test_full_chain_failure(self):
  class TestFatigueAwareness (line 233) | class TestFatigueAwareness:
    method test_progressive_fatigue (line 234) | def test_progressive_fatigue(self):
    method test_model_switch_degrades_fatigue (line 245) | def test_model_switch_degrades_fatigue(self):
    method test_critical_state_detection (line 256) | def test_critical_state_detection(self):
  class TestLockSafety (line 265) | class TestLockSafety:
    method test_concurrent_agent_protection (line 266) | def test_concurrent_agent_protection(self, tmp_path):
    method test_release_allows_reacquire (line 275) | def test_release_allows_reacquire(self, tmp_path):
    method test_release_all_by_session (line 281) | def test_release_all_by_session(self, tmp_path):
  class TestEscalation (line 292) | class TestEscalation:
    method test_auto_escalate_after_failures (line 293) | def test_auto_escalate_after_failures(self, tmp_path):
    method test_resolve_clears_pending (line 302) | def test_resolve_clears_pending(self, tmp_path):
  class TestCheckpointContinuity (line 311) | class TestCheckpointContinuity:
    method test_model_handoff_preserves_state (line 312) | def test_model_handoff_preserves_state(self, tmp_path):
    method test_checkpoint_cleanup (line 326) | def test_checkpoint_cleanup(self, tmp_path):
  class TestCalibrationLearning (line 336) | class TestCalibrationLearning:
    method test_bad_model_gets_penalized (line 337) | def test_bad_model_gets_penalized(self, tmp_path):
    method test_routing_penalizes_uncalibrated (line 352) | def test_routing_penalizes_uncalibrated(self, tmp_path):
  class TestDualPlanning (line 369) | class TestDualPlanning:
    method test_counter_check_runs (line 371) | async def test_counter_check_runs(self):
  class TestObservability (line 392) | class TestObservability:
    method test_signal_recording (line 393) | def test_signal_recording(self, tmp_path):
    method test_signal_log_jsonl (line 406) | def test_signal_log_jsonl(self, tmp_path):
  class TestFullExecutorPipeline (line 417) | class TestFullExecutorPipeline:
    method test_10_task_sprint (line 419) | async def test_10_task_sprint(self, tmp_path):
    method test_sprint_budget_summary (line 470) | async def test_sprint_budget_summary(self, tmp_path):
  class TestProjectRegistry (line 509) | class TestProjectRegistry:
    method test_full_lifecycle (line 510) | def test_full_lifecycle(self, tmp_path):

FILE: maggy/tests/test_bootstrap.py
  function _make_cfg (line 11) | def _make_cfg(tmp_path: Path):
  class TestSeedCIKG (line 30) | class TestSeedCIKG:
    method test_creates_codebase_nodes (line 33) | def test_creates_codebase_nodes(self, tmp_path):
    method test_creates_language_nodes (line 44) | def test_creates_language_nodes(self, tmp_path):
    method test_creates_edges (line 56) | def test_creates_edges(self, tmp_path):
    method test_skips_missing_dirs (line 66) | def test_skips_missing_dirs(self, tmp_path):
    method test_idempotent (line 77) | def test_idempotent(self, tmp_path):
  class TestBootstrap (line 88) | class TestBootstrap:
    method test_calls_services (line 92) | async def test_calls_services(self):
    method test_handles_missing_services (line 104) | async def test_handles_missing_services(self):
    method test_handles_analyze_error (line 114) | async def test_handles_analyze_error(self):

FILE: maggy/tests/test_budget.py
  class TestBudgetTracking (line 10) | class TestBudgetTracking:
    method test_initial_spend_is_zero (line 11) | def test_initial_spend_is_zero(self, mock_cfg):
    method test_record_and_read (line 15) | def test_record_and_read(self, mock_cfg):
    method test_multiple_records_sum (line 20) | def test_multiple_records_sum(self, mock_cfg):
  class TestBudgetStatus (line 27) | class TestBudgetStatus:
    method test_ok_status (line 28) | def test_ok_status(self, mock_cfg):
    method test_warning_status (line 34) | def test_warning_status(self, mock_cfg):
    method test_exhausted_status (line 40) | def test_exhausted_status(self, mock_cfg):
  class TestByProvider (line 47) | class TestByProvider:
    method test_breakdown (line 48) | def test_breakdown(self, mock_cfg):
  class TestIsExhausted (line 59) | class TestIsExhausted:
    method test_not_exhausted (line 60) | def test_not_exhausted(self, mock_cfg):
    method test_exhausted (line 64) | def test_exhausted(self, mock_cfg):
  class TestProviderBudgets (line 70) | class TestProviderBudgets:
    method test_provider_exhaustion_uses_provider_limit (line 71) | def test_provider_exhaustion_uses_provider_limit(self, mock_cfg):
    method test_cheapest_available_skips_exhausted_provider (line 84) | def test_cheapest_available_skips_exhausted_provider(self, mock_cfg):
  class TestTokenTracking (line 96) | class TestTokenTracking:
    method test_initial_tokens_zero (line 97) | def test_initial_tokens_zero(self, mock_cfg):
    method test_record_and_read_tokens (line 102) | def test_record_and_read_tokens(self, mock_cfg):
    method test_tokens_by_provider (line 110) | def test_tokens_by_provider(self, mock_cfg):
    method test_budget_status_includes_tokens (line 117) | def test_budget_status_includes_tokens(self, mock_cfg):
  class TestTaskSpendTracker (line 125) | class TestTaskSpendTracker:
    method test_records_total_cost (line 126) | def test_records_total_cost(self) -> None:
    method test_detects_exceeded_spend (line 132) | def test_detects_exceeded_spend(self) -> None:
    method test_tracks_edit_loops (line 137) | def test_tracks_edit_loops(self) -> None:
    method test_budget_config_has_task_limit (line 144) | def test_budget_config_has_task_limit(self) -> None:

FILE: maggy/tests/test_calibration.py
  function test_records_accuracy_and_error (line 10) | def test_records_accuracy_and_error(tmp_path) -> None:
  function test_unknown_model_returns_zero (line 19) | def test_unknown_model_returns_zero(tmp_path) -> None:
  function test_accuracy_clamps_at_zero_for_large_errors (line 25) | def test_accuracy_clamps_at_zero_for_large_errors(tmp_path) -> None:

FILE: maggy/tests/test_cascade.py
  class TestCascadeNoEscalation (line 11) | class TestCascadeNoEscalation:
    method test_first_model_passes (line 13) | async def test_first_model_passes(self):
  class TestCascadeEscalation (line 36) | class TestCascadeEscalation:
    method test_low_quality_escalates (line 38) | async def test_low_quality_escalates(self):
    method test_max_3_attempts (line 63) | async def test_max_3_attempts(self):
  class TestCascadeFailure (line 86) | class TestCascadeFailure:
    method test_send_failure_escalates (line 88) | async def test_send_failure_escalates(self):
    method test_single_model_no_escalation (line 114) | async def test_single_model_no_escalation(self):
  class TestCascadeAttemptTracking (line 134) | class TestCascadeAttemptTracking:
    method test_attempts_recorded (line 136) | async def test_attempts_recorded(self):

FILE: maggy/tests/test_chat.py
  function _make_cfg (line 12) | def _make_cfg(tmp_path: Path) -> MaggyConfig:
  class TestChatManager (line 20) | class TestChatManager:
    method test_create_session (line 23) | def test_create_session(self, tmp_path):
    method test_create_session_invalid_project (line 35) | def test_create_session_invalid_project(self, tmp_path):
    method test_create_with_project_path (line 42) | def test_create_with_project_path(self, tmp_path):
    method test_create_rejects_outside_path (line 53) | def test_create_rejects_outside_path(self, tmp_path):
    method test_list_sessions (line 62) | def test_list_sessions(self, tmp_path):
    method test_get_session (line 71) | def test_get_session(self, tmp_path):
    method test_get_missing_session (line 80) | def test_get_missing_session(self, tmp_path):
    method test_build_cmd_new_session (line 86) | def test_build_cmd_new_session(self, tmp_path):
    method test_build_cmd_resume (line 99) | def test_build_cmd_resume(self, tmp_path):
    method test_delete_session (line 111) | def test_delete_session(self, tmp_path):
    method test_delete_missing (line 119) | def test_delete_missing(self, tmp_path):
    method test_working_dir_security_bad_key (line 125) | def test_working_dir_security_bad_key(self, tmp_path):
    method test_working_dir_security_bad_path (line 132) | def test_working_dir_security_bad_path(self, tmp_path):
  class TestAutoConnect (line 140) | class TestAutoConnect:
    method test_auto_connect_creates_sessions (line 143) | def test_auto_connect_creates_sessions(self, tmp_path):
    method test_auto_connect_deduplicates (line 155) | def test_auto_connect_deduplicates(self, tmp_path):
    method test_auto_connect_multiple_projects (line 167) | def test_auto_connect_multiple_projects(self, tmp_path):
    method test_auto_connect_skips_empty (line 187) | def test_auto_connect_skips_empty(self, tmp_path):
    method test_find_by_project (line 199) | def test_find_by_project(self, tmp_path):
    method test_find_by_project_missing (line 208) | def test_find_by_project_missing(self, tmp_path):
  class TestMessageQueue (line 215) | class TestMessageQueue:
    method test_enqueue_returns_position (line 218) | def test_enqueue_returns_position(self, tmp_path):
    method test_enqueue_full_returns_negative (line 226) | def test_enqueue_full_returns_negative(self, tmp_path):
    method test_session_has_pending_queue (line 235) | def test_session_has_pending_queue(self, tmp_path):
    method test_send_while_locked_enqueues (line 244) | async def test_send_while_locked_enqueues(self, tmp_path):

FILE: maggy/tests/test_chat_context.py
  class TestPathCandidates (line 20) | class TestPathCandidates:
    method test_basic_path (line 23) | def test_basic_path(self):
    method test_nested_path (line 32) | def test_nested_path(self):
    method test_empty_path (line 41) | def test_empty_path(self):
  class TestMatchFromReport (line 46) | class TestMatchFromReport:
    method test_exact_project_match (line 49) | def test_exact_project_match(self):
    method test_parent_dir_match (line 68) | def test_parent_dir_match(self):
    method test_multiple_matches (line 90) | def test_multiple_matches(self):
    method test_no_match (line 118) | def test_no_match(self):
  class TestMatchHistory (line 132) | class TestMatchHistory:
    method test_uses_report_when_available (line 135) | def test_uses_report_when_available(self):
    method test_returns_empty_when_no_history (line 153) | def test_returns_empty_when_no_history(self):
    method test_returns_empty_when_no_report (line 159) | def test_returns_empty_when_no_report(self):
  class TestFormatRecentPrompts (line 168) | class TestFormatRecentPrompts:
    method test_matching_prompts (line 171) | def test_matching_prompts(self):
    method test_no_matching_prompts (line 182) | def test_no_matching_prompts(self):
    method test_limits_to_five (line 190) | def test_limits_to_five(self):
  class TestResolveSessionId (line 200) | class TestResolveSessionId:
    method test_finds_session_id (line 203) | def test_finds_session_id(self, tmp_path):
    method test_no_match (line 229) | def test_no_match(self, tmp_path):
    method test_missing_file (line 247) | def test_missing_file(self, tmp_path):
  class TestBuildProjectContext (line 257) | class TestBuildProjectContext:
    method test_combines_history_and_prompts (line 260) | def test_combines_history_and_prompts(self):
    method test_empty_when_nothing (line 283) | def test_empty_when_nothing(self):

FILE: maggy/tests/test_chat_routed.py
  class TestBlastEstimation (line 12) | class TestBlastEstimation:
    method test_low_blast_simple_fix (line 15) | def test_low_blast_simple_fix(self):
    method test_high_blast_security (line 18) | def test_high_blast_security(self):
    method test_high_blast_architecture (line 21) | def test_high_blast_architecture(self):
    method test_medium_blast_feature (line 24) | def test_medium_blast_feature(self):
    method test_empty_returns_default (line 28) | def test_empty_returns_default(self):
    method test_retrieval_find_key_low_blast (line 33) | def test_retrieval_find_key_low_blast(self):
    method test_retrieval_show_config (line 37) | def test_retrieval_show_config(self):
    method test_retrieval_check_env (line 40) | def test_retrieval_check_env(self):
    method test_retrieval_where_is_file (line 43) | def test_retrieval_where_is_file(self):
    method test_retrieval_list_endpoints (line 46) | def test_retrieval_list_endpoints(self):
    method test_retrieval_read_file (line 49) | def test_retrieval_read_file(self):
    method test_creation_still_mid (line 52) | def test_creation_still_mid(self):
    method test_multi_step_high (line 57) | def test_multi_step_high(self):
    method test_retrieval_with_action_not_capped (line 61) | def test_retrieval_with_action_not_capped(self):
  class TestTypeEstimation (line 67) | class TestTypeEstimation:
    method test_security_type (line 70) | def test_security_type(self):
    method test_docs_type (line 73) | def test_docs_type(self):
    method test_test_type (line 76) | def test_test_type(self):
    method test_general_default (line 79) | def test_general_default(self):
  class TestRoutedEndpoint (line 83) | class TestRoutedEndpoint:
    method test_send_routed_yields_routing_chunk (line 87) | async def test_send_routed_yields_routing_chunk(self):
  class TestRewardRecording (line 106) | class TestRewardRecording:
    method test_success_records_reward (line 109) | def test_success_records_reward(self):
    method test_error_records_zero_reward (line 121) | def test_error_records_zero_reward(self):
    method test_no_routing_service_noop (line 133) | def test_no_routing_service_noop(self):

FILE: maggy/tests/test_chat_router.py
  function test_blast_hi_scores_low (line 12) | def test_blast_hi_scores_low():
  function test_blast_exit_scores_low (line 17) | def test_blast_exit_scores_low():
  function test_blast_empty_returns_default (line 22) | def test_blast_empty_returns_default():
  function test_blast_security_audit_scores_high (line 27) | def test_blast_security_audit_scores_high():
  function test_blast_fix_typo_scores_low (line 33) | def test_blast_fix_typo_scores_low():
  function test_type_security_detected (line 39) | def test_type_security_detected():
  function test_type_general_default (line 44) | def test_type_general_default():
  function test_type_search_detected (line 49) | def test_type_search_detected():
  function test_type_search_grep (line 54) | def test_type_search_grep():
  function test_blast_search_scores_low (line 59) | def test_blast_search_scores_low():

FILE: maggy/tests/test_chat_stream.py
  class _FakeSession (line 10) | class _FakeSession:
    method __init__ (line 11) | def __init__(self):
  function test_parse_result_extracts_usage (line 15) | def test_parse_result_extracts_usage():
  function test_parse_result_without_usage (line 31) | def test_parse_result_without_usage():
  function test_parse_assistant_text (line 40) | def test_parse_assistant_text():
  function test_parse_captures_session_id (line 51) | def test_parse_captures_session_id():
  function test_parse_result_zero_cost_preserved (line 58) | def test_parse_result_zero_cost_preserved():
  function test_parse_invalid_json (line 73) | def test_parse_invalid_json():

FILE: maggy/tests/test_checkpoint.py
  class TestCheckpoint (line 11) | class TestCheckpoint:
    method test_serialize_round_trip (line 12) | def test_serialize_round_trip(self):
    method test_serialize_sets_timestamp (line 24) | def test_serialize_sets_timestamp(self):
    method test_to_prompt_format (line 30) | def test_to_prompt_format(self):
    method test_to_prompt_minimal (line 45) | def test_to_prompt_minimal(self):
  class TestCreateCheckpoint (line 52) | class TestCreateCheckpoint:
    method test_helper_function (line 53) | def test_helper_function(self):
    method test_defaults (line 66) | def test_defaults(self):

FILE: maggy/tests/test_checkpoint_mgr.py
  function _checkpoint (line 8) | def _checkpoint() -> dict:
  class TestCheckpointManager (line 19) | class TestCheckpointManager:
    method test_write_and_read (line 20) | def test_write_and_read(self, tmp_path) -> None:
    method test_read_missing_returns_none (line 26) | def test_read_missing_returns_none(self, tmp_path) -> None:
    method test_delete_returns_true_when_removed (line 30) | def test_delete_returns_true_when_removed(self, tmp_path) -> None:
    method test_list_checkpoints_returns_session_ids (line 37) | def test_list_checkpoints_returns_session_ids(self, tmp_path) -> None:
    method test_path_traversal_rejected (line 44) | def test_path_traversal_rejected(self, tmp_path) -> None:
    method test_read_corrupt_json_returns_none (line 50) | def test_read_corrupt_json_returns_none(self, tmp_path) -> None:

FILE: maggy/tests/test_cikg.py
  class TestKnowledgeGraph (line 20) | class TestKnowledgeGraph:
    method test_add_and_get_node (line 21) | def test_add_and_get_node(self, tmp_path: Path):
    method test_get_missing_node (line 31) | def test_get_missing_node(self, tmp_path: Path):
    method test_list_nodes_by_type (line 35) | def test_list_nodes_by_type(self, tmp_path: Path):
    method test_list_all_nodes (line 43) | def test_list_all_nodes(self, tmp_path: Path):
  class TestEdges (line 50) | class TestEdges:
    method test_add_and_get_edge (line 51) | def test_add_and_get_edge(self, tmp_path: Path):
    method test_inbound_edges (line 63) | def test_inbound_edges(self, tmp_path: Path):
    method test_neighbors (line 75) | def test_neighbors(self, tmp_path: Path):
  class TestDeleteNode (line 88) | class TestDeleteNode:
    method test_delete_removes_node_and_edges (line 89) | def test_delete_removes_node_and_edges(self, tmp_path: Path):
  class TestQueries (line 102) | class TestQueries:
    method _seed_graph (line 103) | def _seed_graph(self, tmp_path: Path) -> KnowledgeGraphService:
    method test_find_gaps_existing (line 121) | def test_find_gaps_existing(self, tmp_path: Path):
    method test_find_gaps_unknown (line 128) | def test_find_gaps_unknown(self, tmp_path: Path):
    method test_get_landscape (line 135) | def test_get_landscape(self, tmp_path: Path):
    method test_compare_entities (line 142) | def test_compare_entities(self, tmp_path: Path):
  class TestServiceQueries (line 148) | class TestServiceQueries:
    method _seed_graph (line 149) | def _seed_graph(self, tmp_path: Path) -> KnowledgeGraphService:
    method test_find_gaps_raw (line 171) | def test_find_gaps_raw(self, tmp_path: Path):
    method test_compare_entities (line 184) | def test_compare_entities(self, tmp_path: Path):
    method test_segment_landscape (line 192) | def test_segment_landscape(self, tmp_path: Path):
  class TestTypeValidation (line 202) | class TestTypeValidation:
    method test_valid_node_type_accepted (line 203) | def test_valid_node_type_accepted(self):
    method test_invalid_node_type_rejected (line 207) | def test_invalid_node_type_rejected(self):
    method test_valid_edge_type_accepted (line 211) | def test_valid_edge_type_accepted(self):
    method test_invalid_edge_type_rejected (line 215) | def test_invalid_edge_type_rejected(self):

FILE: maggy/tests/test_cli.py
  function _mock_server_running (line 21) | def _mock_server_running(monkeypatch):
  function _mock_get (line 29) | def _mock_get(response_json: dict | list):
  function test_status_shows_health (line 41) | def test_status_shows_health():
  function test_status_json_flag (line 55) | def test_status_json_flag():
  function test_inbox_renders_table (line 67) | def test_inbox_renders_table():
  function test_inbox_empty (line 81) | def test_inbox_empty():
  function test_sessions_renders (line 91) | def test_sessions_renders():
  function test_route_decision (line 107) | def test_route_decision():
  function test_budget_renders (line 123) | def test_budget_renders():
  function test_competitors_news (line 141) | def test_competitors_news():
  function test_models_heatmap (line 154) | def test_models_heatmap():
  function test_server_not_running_starts_it (line 168) | def test_server_not_running_starts_it(monkeypatch):
  function test_stale_port_killed_before_start (line 193) | def test_stale_port_killed_before_start(monkeypatch):
  function test_server_log_written_to_file (line 227) | def test_server_log_written_to_file(monkeypatch, tmp_path):

FILE: maggy/tests/test_cli_chat.py
  function _no_detect (line 40) | def _no_detect(monkeypatch):
  function _setup_new (line 49) | def _setup_new(mock_client):
  function test_chat_creates_session (line 62) | def test_chat_creates_session(mock_client):
  function test_chat_resumes_existing (line 74) | def test_chat_resumes_existing(mock_client):
  function test_chat_routed_streams (line 92) | def test_chat_routed_streams(mock_client):
  function test_chat_direct_mode (line 111) | def test_chat_direct_mode(mock_client):
  function test_chat_history_command (line 130) | def test_chat_history_command(mock_client):
  function test_chat_blast_override (line 140) | def test_chat_blast_override(mock_client):
  function test_chat_ctrl_c_exits (line 159) | def test_chat_ctrl_c_exits(mock_client):
  function test_chat_empty_input_ignored (line 168) | def test_chat_empty_input_ignored(mock_client):
  function test_chat_error_displayed (line 178) | def test_chat_error_displayed(mock_client):
  function test_chat_shows_queued_status (line 191) | def test_chat_shows_queued_status(mock_client):
  function test_chat_shows_warning (line 203) | def test_chat_shows_warning(mock_client):
  function test_chat_exit_word_quits (line 217) | def test_chat_exit_word_quits(mock_client):
  function test_chat_agent_status_rendered (line 228) | def test_chat_agent_status_rendered(mock_client):
  function test_chat_quota_error_shows_guide (line 245) | def test_chat_quota_error_shows_guide(mock_client):
  function test_chat_prompt_uses_angle_bracket (line 262) | def test_chat_prompt_uses_angle_bracket(mock_client):
  function test_screenshot_command_dispatches (line 274) | def test_screenshot_command_dispatches(mock_client):

FILE: maggy/tests/test_cli_discovery.py
  function test_discover_all_returns_profiles (line 12) | def test_discover_all_returns_profiles():
  function test_claude_discovered (line 19) | def test_claude_discovered():
  function test_codex_discovered (line 29) | def test_codex_discovered():
  function test_kimi_discovered (line 38) | def test_kimi_discovered():
  function test_missing_cli (line 47) | def test_missing_cli():
  function test_claude_build_command (line 52) | def test_claude_build_command():
  function test_codex_build_command (line 66) | def test_codex_build_command():
  function test_kimi_build_command (line 79) | def test_kimi_build_command():
  function test_ollama_discovered (line 92) | def test_ollama_discovered():
  function test_ollama_build_command (line 100) | def test_ollama_build_command():
  function test_pi_adapter_uses_discovery (line 111) | def test_pi_adapter_uses_discovery():

FILE: maggy/tests/test_cli_sessions.py
  function test_spawn_creates_session (line 15) | def test_spawn_creates_session(mock_client):
  function test_ps_lists_sessions (line 30) | def test_ps_lists_sessions(mock_client):
  function test_kill_stops_session (line 48) | def test_kill_stops_session(mock_client):

FILE: maggy/tests/test_cli_welcome.py
  function _mock_client (line 10) | def _mock_client():
  function test_render_welcome_shows_project (line 33) | def test_render_welcome_shows_project(capsys):
  function test_render_welcome_shows_budget (line 39) | def test_render_welcome_shows_budget(capsys):
  function test_render_welcome_shows_models (line 45) | def test_render_welcome_shows_models(capsys):
  function test_render_welcome_shows_health (line 51) | def test_render_welcome_shows_health(capsys):
  function test_render_welcome_shows_session_history (line 60) | def test_render_welcome_shows_session_history(capsys):
  function test_dir_shows_cwd_fallback (line 68) | def test_dir_shows_cwd_fallback(capsys):
  function test_models_shows_available_count (line 79) | def test_models_shows_available_count(capsys):
  function test_budget_subscription_welcome (line 88) | def test_budget_subscription_welcome(capsys):

FILE: maggy/tests/test_context_compactor.py
  class TestEstimateTokens (line 14) | class TestEstimateTokens:
    method test_empty_list (line 15) | def test_empty_list(self):
    method test_single_message (line 18) | def test_single_message(self):
    method test_approximation (line 22) | def test_approximation(self):
  class TestShouldCompact (line 28) | class TestShouldCompact:
    method test_below_threshold_no_compact (line 29) | def test_below_threshold_no_compact(self):
    method test_above_threshold_compact (line 33) | def test_above_threshold_compact(self):
    method test_threshold_at_80_pct (line 38) | def test_threshold_at_80_pct(self):
  class TestCompact (line 44) | class TestCompact:
    method test_keeps_recent_messages (line 46) | async def test_keeps_recent_messages(self):
    method test_nothing_to_compact (line 64) | async def test_nothing_to_compact(self):
    method test_summarizer_failure_passthrough (line 76) | async def test_summarizer_failure_passthrough(self):

FILE: maggy/tests/test_contracts.py
  function test_generates_test_code_from_postcondition (line 8) | def test_generates_test_code_from_postcondition() -> None:

FILE: maggy/tests/test_convention_inferrer.py
  function test_collect_fingerprint_includes_files (line 19) | def test_collect_fingerprint_includes_files(tmp_path: Path):
  function test_collect_fingerprint_excludes_noise (line 28) | def test_collect_fingerprint_excludes_noise(tmp_path: Path):
  function test_collect_fingerprint_includes_config (line 40) | def test_collect_fingerprint_includes_config(tmp_path: Path):
  function test_collect_fingerprint_includes_git_log (line 46) | def test_collect_fingerprint_includes_git_log(tmp_path: Path):
  function test_parse_conventions_from_llm_output (line 58) | def test_parse_conventions_from_llm_output():
  function test_parse_ignores_non_convention_lines (line 66) | def test_parse_ignores_non_convention_lines():
  function test_parse_caps_at_10 (line 73) | def test_parse_caps_at_10():
  function test_parse_empty_response (line 78) | def test_parse_empty_response():
  function _seed_project (line 83) | def _seed_project(tmp_path: Path) -> None:
  function test_infer_calls_local_model (line 89) | async def test_infer_calls_local_model(tmp_path: Path):
  function test_infer_falls_back_on_local_failure (line 105) | async def test_infer_falls_back_on_local_failure(tmp_path: Path):
  function test_infer_returns_empty_on_all_failures (line 123) | async def test_infer_returns_empty_on_all_failures(tmp_path: Path):
  function test_ensure_inferred_caches (line 135) | async def test_ensure_inferred_caches(tmp_path: Path):
  function test_ensure_inferred_deduplicates (line 152) | async def test_ensure_inferred_deduplicates(tmp_path: Path):
  function test_all_inferred_have_llm_source (line 170) | async def test_all_inferred_have_llm_source(tmp_path: Path):

FILE: maggy/tests/test_convention_scanner.py
  function test_detects_supabase_migrations (line 14) | def test_detects_supabase_migrations(tmp_path: Path):
  function test_detects_alembic (line 22) | def test_detects_alembic(tmp_path: Path):
  function test_detects_npm (line 30) | def test_detects_npm(tmp_path: Path):
  function test_detects_pnpm (line 38) | def test_detects_pnpm(tmp_path: Path):
  function test_detects_pytest_in_pyproject (line 46) | def test_detects_pytest_in_pyproject(tmp_path: Path):
  function test_detects_ruff_in_pyproject (line 56) | def test_detects_ruff_in_pyproject(tmp_path: Path):
  function test_empty_dir_no_conventions (line 64) | def test_empty_dir_no_conventions(tmp_path: Path):
  function test_all_conventions_have_auto_source (line 70) | def test_all_conventions_have_auto_source(tmp_path: Path):
  function test_conventions_for_merges_project (line 78) | def test_conventions_for_merges_project():
  function test_conventions_for_without_project (line 95) | def test_conventions_for_without_project():
  function test_ensure_scanned_caches (line 112) | def test_ensure_scanned_caches(tmp_path: Path):
  function test_yaml_roundtrip_project_conventions (line 123) | def test_yaml_roundtrip_project_conventions(tmp_path: Path):
  function test_detects_docker_compose (line 145) | def test_detects_docker_compose(tmp_path: Path):
  function test_detects_github_actions (line 153) | def test_detects_github_actions(tmp_path: Path):

FILE: maggy/tests/test_coordination.py
  class TestLockManager (line 11) | class TestLockManager:
    method test_acquire_and_release (line 12) | def test_acquire_and_release(self, tmp_path):
    method test_blocks_other_agent (line 18) | def test_blocks_other_agent(self, tmp_path):
    method test_release_all_returns_count (line 23) | def test_release_all_returns_count(self, tmp_path):
    method test_conflicts_returns_locked_paths (line 31) | def test_conflicts_returns_locked_paths(self, tmp_path):
    method test_expired_locks_are_removed (line 38) | def test_expired_locks_are_removed(self, tmp_path):

FILE: maggy/tests/test_deploy.py
  class TestDeployService (line 8) | class TestDeployService:
    method test_create_session (line 9) | def test_create_session(self):
    method test_get_session (line 16) | def test_get_session(self):
    method test_get_missing_session (line 23) | def test_get_missing_session(self):
    method test_list_sessions (line 27) | def test_list_sessions(self):
    method test_update_status (line 34) | def test_update_status(self):
    method test_update_missing_returns_none (line 44) | def test_update_missing_returns_none(self):
    method test_teardown (line 48) | def test_teardown(self):
    method test_teardown_missing (line 54) | def test_teardown_missing(self):

FILE: maggy/tests/test_discovery.py
  class TestDiscoverLocal (line 23) | class TestDiscoverLocal:
    method test_empty_project (line 24) | def test_empty_project(self, tmp_path: Path):
    method test_detects_github_actions (line 31) | def test_detects_github_actions(self, tmp_path: Path):
    method test_detects_jenkins (line 36) | def test_detects_jenkins(self, tmp_path: Path):
    method test_detects_circleci (line 41) | def test_detects_circleci(self, tmp_path: Path):
    method test_detects_gitlab_ci (line 46) | def test_detects_gitlab_ci(self, tmp_path: Path):
    method test_detects_eslint (line 51) | def test_detects_eslint(self, tmp_path: Path):
    method test_detects_ruff_in_pyproject (line 56) | def test_detects_ruff_in_pyproject(self, tmp_path: Path):
    method test_detects_pre_commit (line 62) | def test_detects_pre_commit(self, tmp_path: Path):
    method test_detects_codeowners (line 67) | def test_detects_codeowners(self, tmp_path: Path):
    method test_detects_dependabot (line 72) | def test_detects_dependabot(self, tmp_path: Path):
    method test_detects_renovate (line 78) | def test_detects_renovate(self, tmp_path: Path):
  class TestDiscoverClis (line 87) | class TestDiscoverClis:
    method test_finds_installed (line 88) | def test_finds_installed(self):
    method test_finds_none (line 96) | def test_finds_none(self):
    method test_finds_all (line 101) | def test_finds_all(self):
  class TestDiscoverRepos (line 111) | class TestDiscoverRepos:
    method test_finds_git_repos (line 112) | def test_finds_git_repos(self, tmp_path: Path):
    method test_skips_hidden_dirs (line 123) | def test_skips_hidden_dirs(self, tmp_path: Path):
    method test_depth_limited (line 133) | def test_depth_limited(self, tmp_path: Path):
    method test_max_30_repos (line 142) | def test_max_30_repos(self, tmp_path: Path):
    method test_no_scan_dirs (line 153) | def test_no_scan_dirs(self, tmp_path: Path):
  class TestDiscoverActiveProjects (line 161) | class TestDiscoverActiveProjects:
    method test_parses_history (line 162) | def test_parses_history(self, tmp_path: Path):
    method test_no_history_file (line 176) | def test_no_history_file(self, tmp_path: Path):
    method test_malformed_json (line 180) | def test_malformed_json(self, tmp_path: Path):
  class TestDiscoverEnvTokens (line 191) | class TestDiscoverEnvTokens:
    method test_detects_tokens (line 192) | def test_detects_tokens(self):
    method test_no_env_tokens (line 199) | def test_no_env_tokens(self):
  class TestParseOrgFromUrl (line 211) | class TestParseOrgFromUrl:
    method test_ssh_url (line 212) | def test_ssh_url(self):
    method test_https_url (line 216) | def test_https_url(self):
    method test_non_github (line 220) | def test_non_github(self):
  class TestFullDiscovery (line 228) | class TestFullDiscovery:
    method test_returns_result (line 229) | def test_returns_result(self, tmp_path: Path):
    method test_populates_repos (line 235) | def test_populates_repos(self, tmp_path: Path):

FILE: maggy/tests/test_dual_planner.py
  function _result (line 13) | def _result(output: str) -> RunResult:
  function test_plan_uses_claude_prompt (line 18) | async def test_plan_uses_claude_prompt() -> None:
  function test_counter_check_uses_codex_prompt (line 36) | async def test_counter_check_uses_codex_prompt() -> None:
  function test_dual_plan_collects_conflicts (line 53) | async def test_dual_plan_collects_conflicts() -> None:

FILE: maggy/tests/test_engram.py
  class TestEngramRecord (line 13) | class TestEngramRecord:
    method test_defaults (line 14) | def test_defaults(self):
    method test_supersede (line 22) | def test_supersede(self):
  class TestEngramStore (line 32) | class TestEngramStore:
    method test_write_and_get (line 33) | def test_write_and_get(self, tmp_path: Path):
    method test_get_missing (line 44) | def test_get_missing(self, tmp_path: Path):
    method test_query_by_namespace (line 48) | def test_query_by_namespace(self, tmp_path: Path):
    method test_query_by_type (line 62) | def test_query_by_type(self, tmp_path: Path):
    method test_count (line 75) | def test_count(self, tmp_path: Path):
  class TestRetrieval (line 86) | class TestRetrieval:
    method _seed (line 87) | def _seed(self, tmp_path: Path) -> EngramStore:
    method test_by_keyword (line 101) | def test_by_keyword(self, tmp_path: Path):
    method test_by_tag (line 107) | def test_by_tag(self, tmp_path: Path):
    method test_by_type (line 113) | def test_by_type(self, tmp_path: Path):
    method test_recent (line 119) | def test_recent(self, tmp_path: Path):
  class TestDiagnostics (line 126) | class TestDiagnostics:
    method test_empty_store (line 127) | def test_empty_store(self, tmp_path: Path):
    method test_healthy_store (line 132) | def test_healthy_store(self, tmp_path: Path):
  class TestEngramSeed (line 147) | class TestEngramSeed:
    method test_seed_writes_all_types (line 150) | def test_seed_writes_all_types(self, tmp_path: Path):
    method test_seed_gives_healthy_score (line 160) | def test_seed_gives_healthy_score(self, tmp_path: Path):
    method test_seed_fills_missing_types (line 167) | def test_seed_fills_missing_types(self, tmp_path: Path):
    method test_seed_skips_when_all_types_present (line 182) | def test_seed_skips_when_all_types_present(self, tmp_path: Path):

FILE: maggy/tests/test_escalation.py
  class TestEscalator (line 8) | class TestEscalator:
    method test_escalate_and_get (line 9) | def test_escalate_and_get(self, tmp_path):
    method test_list_pending_returns_unresolved (line 25) | def test_list_pending_returns_unresolved(self, tmp_path):
    method test_resolve_marks_packet (line 33) | def test_resolve_marks_packet(self, tmp_path):

FILE: maggy/tests/test_event_spine.py
  class TestEventHeader (line 19) | class TestEventHeader:
    method test_defaults (line 20) | def test_defaults(self):
    method test_custom_fields (line 28) | def test_custom_fields(self):
  class TestTypedEvents (line 39) | class TestTypedEvents:
    method test_all_eight_types (line 40) | def test_all_eight_types(self):
    method test_intent_event (line 43) | def test_intent_event(self):
    method test_execution_event (line 51) | def test_execution_event(self):
    method test_outcome_event (line 60) | def test_outcome_event(self):
  class TestEventStore (line 66) | class TestEventStore:
    method test_write_and_query (line 67) | def test_write_and_query(self, tmp_path: Path):
    method test_query_by_type (line 74) | def test_query_by_type(self, tmp_path: Path):
    method test_count (line 83) | def test_count(self, tmp_path: Path):
    method test_limit (line 93) | def test_limit(self, tmp_path: Path):
  class TestEventEmitter (line 102) | class TestEventEmitter:
    method test_emit_returns_id (line 103) | def test_emit_returns_id(self, tmp_path: Path):
    method test_emit_invalid_raises (line 110) | def test_emit_invalid_raises(self, tmp_path: Path):
    method test_trace (line 117) | def test_trace(self, tmp_path: Path):
    method test_count (line 129) | def test_count(self, tmp_path: Path):
    method test_query_by_project (line 136) | def test_query_by_project(self, tmp_path: Path):

FILE: maggy/tests/test_executor_routing.py
  function _session (line 17) | def _session() -> dict[str, str]:
  function _task (line 30) | def _task(blast_score: int, task_type: str) -> Task:
  function _ctx (line 43) | def _ctx(session: dict, task: Task, wd: str) -> SessionCtx:
  function _patch_executor (line 47) | def _patch_executor(executor, monkeypatch):
  function test_plan_mode_routes_high_blast_to_claude (line 68) | async def test_plan_mode_routes_high_blast_to_claude(
  function test_plan_records_spend (line 97) | async def test_plan_records_spend(mock_cfg, tmp_path, monkeypatch):
  function test_tdd_high_blast_calls_dual_planner (line 124) | async def test_tdd_high_blast_calls_dual_planner(
  function test_locks_released_after_run (line 145) | async def test_locks_released_after_run(
  function test_fatigue_tracked (line 162) | async def test_fatigue_tracked(mock_cfg, tmp_path, monkeypatch):
  function test_conventions_in_prompts (line 175) | async def test_conventions_in_prompts(
  function test_tdd_calls_reviewer (line 205) | async def test_tdd_calls_reviewer(mock_cfg, tmp_path, monkeypatch):
  function test_review_retry_on_low_score (line 227) | async def test_review_retry_on_low_score(
  function test_status_callback_fires (line 253) | async def test_status_callback_fires(
  function test_status_shows_model_name (line 273) | async def test_status_shows_model_name(

FILE: maggy/tests/test_fatigue.py
  class TestFatigueProfile (line 13) | class TestFatigueProfile:
    method test_zero_usage_no_fatigue (line 14) | def test_zero_usage_no_fatigue(self):
    method test_full_context_high_fatigue (line 19) | def test_full_context_high_fatigue(self):
    method test_half_context_moderate_fatigue (line 26) | def test_half_context_moderate_fatigue(self):
    method test_zero_context_window_safe (line 34) | def test_zero_context_window_safe(self):
  class TestShouldCheckpoint (line 39) | class TestShouldCheckpoint:
    method test_below_threshold (line 40) | def test_below_threshold(self):
    method test_above_threshold (line 47) | def test_above_threshold(self):
    method test_custom_threshold (line 54) | def test_custom_threshold(self):
  class TestCreateProfile (line 62) | class TestCreateProfile:
    method test_known_model (line 63) | def test_known_model(self):
    method test_unknown_model_defaults (line 67) | def test_unknown_model_defaults(self):
  class TestCompareFatigue (line 72) | class TestCompareFatigue:
    method test_sorted_by_fatigue (line 73) | def test_sorted_by_fatigue(self):

FILE: maggy/tests/test_forge.py
  class TestForgeRegistry (line 12) | class TestForgeRegistry:
    method test_empty_without_forge (line 13) | def test_empty_without_forge(self):
    method test_loads_from_forge_path (line 17) | def test_loads_from_forge_path(self):
    method test_search (line 24) | def test_search(self):
    method test_get_missing (line 32) | def test_get_missing(self):
    method test_set_enabled (line 36) | def test_set_enabled(self):
  class TestGapDetector (line 44) | class TestGapDetector:
    method test_first_record_no_trigger (line 45) | def test_first_record_no_trigger(self):
    method test_trigger_at_threshold (line 49) | def test_trigger_at_threshold(self):
    method test_no_double_trigger (line 55) | def test_no_double_trigger(self):
    method test_list_gaps (line 61) | def test_list_gaps(self):
    method test_reset (line 71) | def test_reset(self):
  class TestForgeConnector (line 80) | class TestForgeConnector:
    method test_status (line 81) | def test_status(self):
    method test_report_gap (line 87) | def test_report_gap(self):
    method test_search_tools_empty (line 92) | def test_search_tools_empty(self):
    method test_with_real_forge (line 96) | def test_with_real_forge(self):

FILE: maggy/tests/test_heartbeat.py
  class TestJob (line 16) | class TestJob:
    method test_defaults (line 17) | def test_defaults(self):
    method test_is_due_no_last_run (line 27) | def test_is_due_no_last_run(self):
    method test_is_due_after_interval (line 32) | def test_is_due_after_interval(self):
    method test_not_due_before_interval (line 40) | def test_not_due_before_interval(self):
  class TestSchedulerRegister (line 51) | class TestSchedulerRegister:
    method test_register_job (line 52) | def test_register_job(self):
    method test_register_duplicate_raises (line 58) | def test_register_duplicate_raises(self):
    method test_status_returns_list (line 65) | def test_status_returns_list(self):
  class TestSchedulerTick (line 76) | class TestSchedulerTick:
    method test_tick_runs_due_jobs (line 78) | async def test_tick_runs_due_jobs(self):
    method test_tick_skips_disabled (line 86) | async def test_tick_skips_disabled(self):
    method test_tick_records_error (line 95) | async def test_tick_records_error(self):
    method test_tick_increments_count (line 103) | async def test_tick_increments_count(self):
  class TestSchedulerTrigger (line 112) | class TestSchedulerTrigger:
    method test_trigger_runs_job (line 114) | async def test_trigger_runs_job(self):
    method test_trigger_unknown_raises (line 123) | async def test_trigger_unknown_raises(self):
  class TestSchedulerLifecycle (line 129) | class TestSchedulerLifecycle:
    method test_start_stop (line 131) | async def test_start_stop(self):
  class TestJobs (line 146) | class TestJobs:
    method test_refresh_history_calls_analyze (line 148) | async def test_refresh_history_calls_analyze(self):
    method test_refresh_history_skips_none (line 158) | async def test_refresh_history_skips_none(self):
    method test_self_improve_calls_analyze (line 165) | async def test_self_improve_calls_analyze(self):
    method test_self_improve_skips_none (line 175) | async def test_self_improve_skips_none(self):

FILE: maggy/tests/test_history.py
  function _make_session (line 21) | def _make_session(
  function sample_sessions (line 45) | def sample_sessions() -> list[SessionEntry]:
  class TestAnalyzer (line 65) | class TestAnalyzer:
    method test_build_report_empty (line 68) | def test_build_report_empty(self):
    method test_build_report_with_data (line 75) | def test_build_report_with_data(self, sample_sessions):
    method test_aggregate_by_provider (line 82) | def test_aggregate_by_provider(self, sample_sessions):
    method test_aggregate_by_project (line 90) | def test_aggregate_by_project(self, sample_sessions):
    method test_compute_time_distribution (line 97) | def test_compute_time_distribution(self, sample_sessions):
    method test_detect_patterns (line 105) | def test_detect_patterns(self, sample_sessions):
    method test_extract_top_topics (line 113) | def test_extract_top_topics(self, sample_sessions):
  class TestHistoryStore (line 123) | class TestHistoryStore:
    method test_save_and_load_sessions (line 126) | def test_save_and_load_sessions(self, tmp_path: Path):
    method test_load_sessions_by_provider (line 134) | def test_load_sessions_by_provider(self, tmp_path: Path):
    method test_save_and_load_report (line 146) | def test_save_and_load_report(self, tmp_path: Path):
    method test_load_report_empty (line 160) | def test_load_report_empty(self, tmp_path: Path):
  class TestHistoryService (line 169) | class TestHistoryService:
    method _isolated_dirs (line 172) | def _isolated_dirs(self, tmp_path: Path) -> dict:
    method test_analyze_no_parsers (line 180) | def test_analyze_no_parsers(self, tmp_path: Path):
    method test_analyze_with_claude (line 189) | def test_analyze_with_claude(self, tmp_path: Path):
    method test_get_report_cached (line 208) | def test_get_report_cached(self, tmp_path: Path):
    method test_get_sessions (line 227) | def test_get_sessions(self, tmp_path: Path):

FILE: maggy/tests/test_history_parsers.py
  class TestClaudeParser (line 18) | class TestClaudeParser:
    method test_not_available_missing_dir (line 21) | def test_not_available_missing_dir(self, tmp_path: Path):
    method test_available_with_history (line 25) | def test_available_with_history(self, tmp_path: Path):
    method test_session_count_empty (line 32) | def test_session_count_empty(self, tmp_path: Path):
    method test_session_count (line 39) | def test_session_count(self, tmp_path: Path):
    method test_parse_sessions (line 51) | def test_parse_sessions(self, tmp_path: Path):
    method test_parse_empty_history (line 69) | def test_parse_empty_history(self, tmp_path: Path):
    method test_parse_with_transcript (line 76) | def test_parse_with_transcript(self, tmp_path: Path):
  class TestCodexParser (line 103) | class TestCodexParser:
    method test_not_available_missing_dir (line 106) | def test_not_available_missing_dir(self, tmp_path: Path):
    method test_available_with_index (line 110) | def test_available_with_index(self, tmp_path: Path):
    method test_session_count (line 117) | def test_session_count(self, tmp_path: Path):
    method test_parse_sessions (line 128) | def test_parse_sessions(self, tmp_path: Path):
    method test_parse_empty (line 148) | def test_parse_empty(self, tmp_path: Path):
  class TestKimiParser (line 160) | class TestKimiParser:
    method test_not_available_missing_dir (line 163) | def test_not_available_missing_dir(self, tmp_path: Path):
    method test_available_with_sessions (line 167) | def test_available_with_sessions(self, tmp_path: Path):
    method test_session_count (line 173) | def test_session_count(self, tmp_path: Path):
    method test_parse_sessions (line 184) | def test_parse_sessions(self, tmp_path: Path):
    method test_parse_empty (line 209) | def test_parse_empty(self, tmp_path: Path):
    method test_parse_missing_wire (line 215) | def test_parse_missing_wire(self, tmp_path: Path):

FILE: maggy/tests/test_improve.py
  class TestModels (line 20) | class TestModels:
    method test_recommendation_defaults (line 21) | def test_recommendation_defaults(self):
    method test_signal_bundle_defaults (line 30) | def test_signal_bundle_defaults(self):
    method test_improvement_report (line 35) | def test_improvement_report(self):
  class TestCollectRouting (line 49) | class TestCollectRouting:
    method test_collects_heatmap (line 50) | def test_collects_heatmap(self):
    method test_flags_underperformers (line 60) | def test_flags_underperformers(self):
  class TestCollectEvents (line 70) | class TestCollectEvents:
    method test_calculates_failure_rate (line 71) | def test_calculates_failure_rate(self):
    method test_empty_events (line 83) | def test_empty_events(self):
  class TestCollectHistory (line 91) | class TestCollectHistory:
    method test_returns_patterns (line 92) | def test_returns_patterns(self):
    method test_no_report (line 103) | def test_no_report(self):
  class TestCollectForge (line 111) | class TestCollectForge:
    method test_returns_gaps (line 112) | def test_returns_gaps(self):
  class TestCollectEngram (line 122) | class TestCollectEngram:
    method test_returns_health (line 123) | def test_returns_health(self):
  class TestCollectBudget (line 136) | class TestCollectBudget:
    method test_returns_status (line 137) | def test_returns_status(self):
  class TestCollectAll (line 147) | class TestCollectAll:
    method test_skips_none_services (line 148) | def test_skips_none_services(self):
  class TestAnalyzeRouting (line 162) | class TestAnalyzeRouting:
    method test_flags_underperformers (line 163) | def test_flags_underperformers(self):
    method test_no_issues (line 174) | def test_no_issues(self):
  class TestAnalyzeFailures (line 180) | class TestAnalyzeFailures:
    method test_flags_high_failure (line 181) | def test_flags_high_failure(self):
    method test_ok_rate (line 188) | def test_ok_rate(self):
  class TestAnalyzeUsage (line 194) | class TestAnalyzeUsage:
    method test_flags_low_usage (line 195) | def test_flags_low_usage(self):
    method test_no_sessions (line 205) | def test_no_sessions(self):
  class TestAnalyzeGaps (line 211) | class TestAnalyzeGaps:
    method test_surfaces_gaps (line 212) | def test_surfaces_gaps(self):
  class TestAnalyzeMemory (line 222) | class TestAnalyzeMemory:
    method test_flags_low_health (line 223) | def test_flags_low_health(self):
    method test_healthy (line 230) | def test_healthy(self):
  class TestAnalyzeCost (line 236) | class TestAnalyzeCost:
    method test_flags_high_util (line 237) | def test_flags_high_util(self):
    method test_ok_util (line 244) | def test_ok_util(self):
  class TestAnalyzeAll (line 250) | class TestAnalyzeAll:
    method test_merges_all (line 251) | def test_merges_all(self):
  class TestIntrospector (line 273) | class TestIntrospector:
    method test_analyze_empty_state (line 274) | def test_analyze_empty_state(self):
    method test_get_report_none_initially (line 285) | def test_get_report_none_initially(self):
    method test_get_report_after_analyze (line 294) | def test_get_report_after_analyze(self):
    method test_health_summary_populated (line 306) | def test_health_summary_populated(self):

FILE: maggy/tests/test_lexon.py
  class TestTerminology (line 12) | class TestTerminology:
    method test_resolve_canonical (line 13) | def test_resolve_canonical(self):
    method test_resolve_synonym (line 17) | def test_resolve_synonym(self):
    method test_resolve_unknown (line 21) | def test_resolve_unknown(self):
    method test_add_alias (line 25) | def test_add_alias(self):
    method test_add_alias_unknown_canonical (line 30) | def test_add_alias_unknown_canonical(self):
  class TestDisambiguate (line 35) | class TestDisambiguate:
    method test_high_confidence_resolves (line 36) | def test_high_confidence_resolves(self):
    method test_mid_confidence_self_clarify (line 42) | def test_mid_confidence_self_clarify(self):
    method test_low_confidence_user_clarify (line 47) | def test_low_confidence_user_clarify(self):
    method test_very_low_rejects (line 52) | def test_very_low_rejects(self):
  class TestPersonalization (line 57) | class TestPersonalization:
    method test_record_and_top (line 58) | def test_record_and_top(self):
    method test_preferred_alias (line 66) | def test_preferred_alias(self):
    method test_correction (line 71) | def test_correction(self):
  class TestLexonRouter (line 77) | class TestLexonRouter:
    method test_known_intent (line 78) | def test_known_intent(self):
    method test_unknown_intent (line 84) | def test_unknown_intent(self):
    method test_learn_and_recall (line 89) | def test_learn_and_recall(self):
    method test_multiple_candidates (line 96) | def test_multiple_candidates(self):
    method test_manifest_overrides_default_tools (line 101) | def test_manifest_overrides_default_tools(self):
  class TestLexonRecord (line 111) | class TestLexonRecord:
    method test_ambiguous (line 112) | def test_ambiguous(self):
    method test_not_ambiguous (line 116) | def test_not_ambiguous(self):
    method test_needs_user_input (line 120) | def test_needs_user_input(self):

FILE: maggy/tests/test_mesh.py
  class TestProtocol (line 19) | class TestProtocol:
    method test_serialize_round_trip (line 20) | def test_serialize_round_trip(self):
    method test_share_message (line 27) | def test_share_message(self):
  class TestPeerDiscovery (line 36) | class TestPeerDiscovery:
    method test_register_and_list (line 37) | def test_register_and_list(self):
    method test_unregister (line 46) | def test_unregister(self):
    method test_update_seen (line 55) | def test_update_seen(self):
  class TestProvenance (line 67) | class TestProvenance:
    method test_no_hop_full_confidence (line 68) | def test_no_hop_full_confidence(self):
    method test_decay_per_hop (line 72) | def test_decay_per_hop(self):
    method test_add_hop (line 78) | def test_add_hop(self):
    method test_min_confidence (line 83) | def test_min_confidence(self):
  class TestQuarantine (line 90) | class TestQuarantine:
    method test_quarantine_and_list (line 91) | def test_quarantine_and_list(self):
    method test_promote (line 97) | def test_promote(self):
    method test_promote_missing (line 103) | def test_promote_missing(self):
  class TestSync (line 108) | class TestSync:
    method test_accept_high_confidence (line 109) | def test_accept_high_confidence(self):
    method test_quarantine_low_confidence (line 122) | def test_quarantine_low_confidence(self):
  class TestTransport (line 136) | class TestTransport:
    method test_hmac_round_trip (line 137) | def test_hmac_round_trip(self):
    method test_hmac_mismatch (line 141) | def test_hmac_mismatch(self):

FILE: maggy/tests/test_mesh_network.py
  class TestEffectiveOrgs (line 18) | class TestEffectiveOrgs:
    method test_merge_scanned_and_manual (line 19) | def test_merge_scanned_and_manual(self):
    method test_excludes_orgs (line 26) | def test_excludes_orgs(self):
    method test_deduplicates (line 35) | def test_deduplicates(self):
    method test_empty_inputs (line 42) | def test_empty_inputs(self):
  class TestDeriveOrgKey (line 50) | class TestDeriveOrgKey:
    method test_different_orgs_produce_different_keys (line 51) | def test_different_orgs_produce_different_keys(self):
    method test_deterministic (line 57) | def test_deterministic(self):
    method test_returns_hex_string (line 63) | def test_returns_hex_string(self):
  class TestSignVerify (line 69) | class TestSignVerify:
    method test_roundtrip (line 70) | def test_roundtrip(self):
    method test_wrong_key_fails (line 79) | def test_wrong_key_fails(self):
    method test_invalid_json_fails (line 87) | def test_invalid_json_fails(self):
  class TestBuildNetwork (line 96) | class TestBuildNetwork:
    method test_creates_network (line 97) | def test_creates_network(self, tmp_path: Path):
    method test_isolated_org_keys (line 105) | def test_isolated_org_keys(self, tmp_path: Path):
    method test_status_returns_counts (line 113) | def test_status_returns_counts(self, tmp_path: Path):
  function _make_cfg (line 128) | def _make_cfg(**overrides):
  class TestMeshManager (line 141) | class TestMeshManager:
    method test_add_and_get_network (line 142) | def test_add_and_get_network(self, tmp_path: Path):
    method test_missing_network_returns_none (line 151) | def test_missing_network_returns_none(self, tmp_path: Path):
    method test_list_networks (line 158) | def test_list_networks(self, tmp_path: Path):
    method test_total_peers_across_networks (line 168) | def test_total_peers_across_networks(self, tmp_path: Path):
    method test_resolve_address_tunnel (line 180) | def test_resolve_address_tunnel(self, tmp_path: Path):
    method test_resolve_address_local (line 188) | def test_resolve_address_local(self, tmp_path: Path):
  class TestPublisher (line 199) | class TestPublisher:
    method test_collect_scores_skips_low_count (line 200) | def test_collect_scores_skips_low_count(self):
    method test_collect_scores_includes_high_count (line 210) | def test_collect_scores_includes_high_count(self):
    method test_collect_gaps (line 221) | def test_collect_gaps(self):
    method test_collect_policies_filters_severity (line 230) | def test_collect_policies_filters_severity(self):
    method test_collect_all_none_services (line 251) | def test_collect_all_none_services(self):
  class TestGitDiscovery (line 261) | class TestGitDiscovery:
    method test_ensure_repo_exists (line 263) | async def test_ensure_repo_exists(self):
    method test_ensure_repo_creates_new (line 278) | async def test_ensure_repo_creates_new(self):
    method test_read_peers_empty (line 296) | async def test_read_peers_empty(self):
    method test_announce_success (line 311) | async def test_announce_success(self):
    method test_remove_announcement (line 333) | async def test_remove_announcement(self):
  class TestPromoteFlow (line 357) | class TestPromoteFlow:
    method test_promote_accepts_into_sync (line 358) | def test_promote_accepts_into_sync(self, tmp_path: Path):
    method test_promote_nonexistent_returns_false (line 380) | def test_promote_nonexistent_returns_false(
  class TestReplayProtection (line 394) | class TestReplayProtection:
    method test_stale_message_rejected (line 395) | def test_stale_message_rejected(self):
  class TestSqliteReload (line 417) | class TestSqliteReload:
    method test_peers_reload_from_store (line 418) | def test_peers_reload_from_store(self, tmp_path: Path):
    method test_sync_reload_from_store (line 432) | def test_sync_reload_from_store(self, tmp_path: Path):

FILE: maggy/tests/test_mesh_store.py
  function store (line 13) | def store(tmp_path: Path) -> MeshStore:
  class TestPeerCRUD (line 17) | class TestPeerCRUD:
    method test_upsert_and_get (line 18) | def test_upsert_and_get(self, store: MeshStore):
    method test_list_by_org (line 24) | def test_list_by_org(self, store: MeshStore):
    method test_list_all (line 30) | def test_list_all(self, store: MeshStore):
    method test_remove_peer (line 35) | def test_remove_peer(self, store: MeshStore):
    method test_remove_missing (line 40) | def test_remove_missing(self, store: MeshStore):
    method test_upsert_updates (line 43) | def test_upsert_updates(self, store: MeshStore):
  class TestMemoryCRUD (line 51) | class TestMemoryCRUD:
    method test_write_and_list (line 52) | def test_write_and_list(self, store: MeshStore):
    method test_scoped_by_org (line 58) | def test_scoped_by_org(self, store: MeshStore):
    method test_upsert_memory (line 64) | def test_upsert_memory(self, store: MeshStore):
  class TestQuarantineCRUD (line 72) | class TestQuarantineCRUD:
    method test_quarantine_and_list (line 73) | def test_quarantine_and_list(self, store: MeshStore):
    method test_promote (line 79) | def test_promote(self, store: MeshStore):
    method test_promote_missing (line 84) | def test_promote_missing(self, store: MeshStore):
    method test_scoped_by_org (line 87) | def test_scoped_by_org(self, store: MeshStore):

FILE: maggy/tests/test_mesh_ws.py
  function _build_app_with_mesh (line 27) | def _build_app_with_mesh(tmp_dir: Path | None = None):
  class TestWsServerNoMesh (line 51) | class TestWsServerNoMesh:
    method test_no_mesh_closes_connection (line 52) | def test_no_mesh_closes_connection(self):
  class TestWsServerAuth (line 66) | class TestWsServerAuth:
    method test_invalid_json_closes (line 67) | def test_invalid_json_closes(self):
    method test_wrong_org_closes (line 75) | def test_wrong_org_closes(self):
  class TestWsServerHello (line 88) | class TestWsServerHello:
    method test_valid_hello_gets_reply (line 89) | def test_valid_hello_gets_reply(self):
  class TestMeshClient (line 107) | class TestMeshClient:
    method test_init (line 108) | def test_init(self):
    method test_is_connected_false (line 113) | def test_is_connected_false(self):
    method test_send_no_connection (line 119) | async def test_send_no_connection(self):
    method test_broadcast_empty (line 127) | async def test_broadcast_empty(self):
    method test_close_all_empty (line 135) | async def test_close_all_empty(self):

FILE: maggy/tests/test_mnemos_fatigue.py
  class TestFatigueTracker (line 13) | class TestFatigueTracker:
    method test_composite_and_state_ok (line 14) | def test_composite_and_state_ok(self):
    method test_rejects_invalid_dimension (line 23) | def test_rejects_invalid_dimension(self):
    method test_model_switch_increases_reread_ratio (line 28) | def test_model_switch_increases_reread_ratio(self):
    method test_state_thresholds (line 35) | def test_state_thresholds(self):
  class TestSignalLog (line 45) | class TestSignalLog:
    method test_append_and_recent (line 46) | def test_append_and_recent(self, tmp_path: Path):

FILE: maggy/tests/test_monday_provider.py
  function provider (line 11) | def provider():
  function test_provider_name (line 17) | def test_provider_name(provider):
  function test_to_task_maps_fields (line 21) | def test_to_task_maps_fields(provider):
  function test_list_tasks_parses_items (line 41) | async def test_list_tasks_parses_items(provider, monkeypatch):
  function test_list_tasks_empty_board (line 66) | async def test_list_tasks_empty_board(provider, monkeypatch):
  function test_get_task_by_id (line 86) | async def test_get_task_by_id(provider, monkeypatch):
  function test_get_task_not_found (line 109) | async def test_get_task_not_found(provider, monkeypatch):

FILE: maggy/tests/test_monitor.py
  function svc (line 14) | def svc(tmp_path):
  function test_add_and_list (line 18) | def test_add_and_list(svc):
  function test_remove (line 27) | def test_remove(svc):
  function test_is_new_unseen (line 34) | def test_is_new_unseen(svc):
  function test_mark_seen_not_new (line 39) | def test_mark_seen_not_new(svc):
  function test_add_duplicate_updates (line 45) | def test_add_duplicate_updates(svc):
  function test_default_interval (line 54) | def test_default_interval(svc):
  function test_status_summary (line 61) | def test_status_summary(svc):
  function test_poll_github_prs (line 70) | async def test_poll_github_prs(svc, monkeypatch):

FILE: maggy/tests/test_multimodel_integration.py
  function _project_cfg (line 35) | def _project_cfg(tmp_path) -> MaggyConfig:
  function _task (line 53) | def _task(blast: int, ttype: str, title: str) -> Task:
  class TestRoutingDecisions (line 77) | class TestRoutingDecisions:
    method test_low_blast_routes_to_cheap_tier (line 80) | def test_low_blast_routes_to_cheap_tier(self, tmp_path):
    method test_mid_blast_routes_to_cheapest_capable (line 92) | def test_mid_blast_routes_to_cheapest_capable(self, tmp_path):
    method test_blast_6_routes_to_codex (line 99) | def test_blast_6_routes_to_codex(self, tmp_path):
    method test_high_blast_routes_to_codex_or_claude (line 106) | def test_high_blast_routes_to_codex_or_claude(self, tmp_path):
    method test_security_routes_to_claude (line 113) | def test_security_routes_to_claude(self, tmp_path):
  class TestExecutorPipeline (line 130) | class TestExecutorPipeline:
    method test_distributes_across_models (line 134) | async def test_distributes_across_models(self, tmp_path):
  class TestCrossProviderBudget (line 183) | class TestCrossProviderBudget:
    method test_spend_tracked_per_provider (line 184) | def test_spend_tracked_per_provider(self, tmp_path):
    method test_task_spend_halts_at_limit (line 195) | def test_task_spend_halts_at_limit(self):
  class TestFallbackChain (line 206) | class TestFallbackChain:
    method test_falls_back_on_failure (line 208) | async def test_falls_back_on_failure(self):
  class TestCheckpointHandoff (line 236) | class TestCheckpointHandoff:
    method test_checkpoint_roundtrip (line 237) | def test_checkpoint_roundtrip(self, tmp_path):
  class TestDualPlanning (line 256) | class TestDualPlanning:
    method test_plan_and_review_use_separate_models (line 258) | async def test_plan_and_review_use_separate_models(self):
  class TestFatigueAcrossModels (line 280) | class TestFatigueAcrossModels:
    method test_model_switch_increases_fatigue (line 281) | def test_model_switch_increases_fatigue(self):
  class TestLockCoordination (line 297) | class TestLockCoordination:
    method test_agents_cant_clobber_each_other (line 298) | def test_agents_cant_clobber_each_other(self, tmp_path):

FILE: maggy/tests/test_observability.py
  function test_records_and_reads_recent_signals (line 8) | def test_records_and_reads_recent_signals(tmp_path) -> None:
  function test_limits_recent_signals (line 20) | def test_limits_recent_signals(tmp_path) -> None:

FILE: maggy/tests/test_output_reviewer.py
  class TestParseReview (line 13) | class TestParseReview:
    method test_parses_score_and_reason (line 14) | def test_parses_score_and_reason(self):
    method test_parses_score_only (line 20) | def test_parses_score_only(self):
    method test_no_score_returns_default (line 25) | def test_no_score_returns_default(self):
    method test_score_out_of_range_clamped (line 30) | def test_score_out_of_range_clamped(self):
    method test_score_from_inline_text (line 34) | def test_score_from_inline_text(self):
  class TestReviewOutput (line 39) | class TestReviewOutput:
    method test_returns_review_result (line 41) | async def test_returns_review_result(self):
    method test_failure_returns_passthrough (line 59) | async def test_failure_returns_passthrough(self):
    method test_exception_returns_passthrough (line 77) | async def test_exception_returns_passthrough(self):
    method test_uses_local_model (line 90) | async def test_uses_local_model(self):
    method test_prompt_contains_step_and_output (line 110) | async def test_prompt_contains_step_and_output(self):

FILE: maggy/tests/test_pi_adapter.py
  class TestModelRegistry (line 16) | class TestModelRegistry:
    method test_default_models_loaded (line 17) | def test_default_models_loaded(self):
    method test_get_known_model (line 21) | def test_get_known_model(self):
    method test_get_unknown_returns_none (line 27) | def test_get_unknown_returns_none(self):
    method test_custom_models (line 31) | def test_custom_models(self):
  class TestFallbackChain (line 40) | class TestFallbackChain:
    method test_chain_excludes_start (line 41) | def test_chain_excludes_start(self):
    method test_chain_ordered_by_cost (line 46) | def test_chain_ordered_by_cost(self):
    method test_unknown_start_returns_all (line 51) | def test_unknown_start_returns_all(self):
  class TestQuotaDetection (line 57) | class TestQuotaDetection:
    method test_detects_rate_limit (line 58) | def test_detects_rate_limit(self):
    method test_detects_429 (line 62) | def test_detects_429(self):
    method test_clean_output_no_quota (line 66) | def test_clean_output_no_quota(self):
  class TestBuildCommand (line 71) | class TestBuildCommand:
    method test_claude_command_format (line 72) | def test_claude_command_format(self):
    method test_non_claude_command (line 80) | def test_non_claude_command(self):
  class _FakeStream (line 91) | class _FakeStream:
    method __init__ (line 92) | def __init__(self, lines: list[str]):
    method readline (line 96) | def readline(self) -> str:
    method write (line 101) | def write(self, text: str) -> None:
    method flush (line 104) | def flush(self) -> None:
  class _FakeProcess (line 108) | class _FakeProcess:
    method __init__ (line 109) | def __init__(self, stdout_lines: list[str]):
  class TestRpcMode (line 114) | class TestRpcMode:
    method test_detect_pi_uses_path_lookup (line 115) | def test_detect_pi_uses_path_lookup(self):
    method test_send_rpc_serializes_command (line 120) | def test_send_rpc_serializes_command(self):
    method test_switch_model_uses_rpc (line 128) | def test_switch_model_uses_rpc(self):
  class TestPromptResult (line 141) | class TestPromptResult:
    method test_parses_json_output (line 142) | def test_parses_json_output(self):
    method test_plain_text_fallback (line 156) | def test_plain_text_fallback(self):
    method test_json_error_preserves_usage (line 164) | def test_json_error_preserves_usage(self):
  class TestStreaming (line 177) | class TestStreaming:
    method test_stream_events_reads_jsonl (line 179) | async def test_stream_events_reads_jsonl(self):

FILE: maggy/tests/test_planning.py
  class TestPlanModels (line 14) | class TestPlanModels:
    method test_plan_step_count (line 15) | def test_plan_step_count(self):
    method test_plan_diff_agreement_ratio (line 25) | def test_plan_diff_agreement_ratio(self):
    method test_plan_diff_empty (line 34) | def test_plan_diff_empty(self):
  class TestPlanningService (line 40) | class TestPlanningService:
    method test_below_threshold_single_plan (line 41) | def test_below_threshold_single_plan(self, mock_cfg):
    method test_above_threshold_dual_plan (line 48) | def test_above_threshold_dual_plan(self, mock_cfg):
    method test_generate_plan (line 57) | def test_generate_plan(self, mock_cfg):
    method test_diff_plans_identical (line 64) | def test_diff_plans_identical(self, mock_cfg):
    method test_should_dual_plan_boundary (line 71) | def test_should_dual_plan_boundary(self, mock_cfg):
  class TestSimilarity (line 78) | class TestSimilarity:
    method test_similar_strings (line 79) | def test_similar_strings(self):
    method test_dissimilar_strings (line 85) | def test_dissimilar_strings(self):
    method test_empty_string (line 91) | def test_empty_string(self):

FILE: maggy/tests/test_registry.py
  class TestProjectConfigParsing (line 9) | class TestProjectConfigParsing:
    method test_from_dict_parses_projects (line 10) | def test_from_dict_parses_projects(self):
  class TestProjectRegistry (line 37) | class TestProjectRegistry:
    method test_registry_crud (line 38) | def test_registry_crud(self):
    method test_add_duplicate_raises (line 60) | def test_add_duplicate_raises(self):

FILE: maggy/tests/test_repl_cmds.py
  class FakeState (line 21) | class FakeState:
  function _mock_client (line 27) | def _mock_client():
  function test_dispatch_stats (line 61) | def test_dispatch_stats(capsys):
  function test_dispatch_unknown (line 69) | def test_dispatch_unknown():
  function test_cmd_stats (line 75) | def test_cmd_stats(capsys):
  function test_cmd_budget (line 82) | def test_cmd_budget(capsys):
  function test_cmd_route (line 89) | def test_cmd_route(capsys):
  function test_cmd_models (line 96) | def test_cmd_models(capsys):
  function test_cmd_use_sets_models (line 103) | def test_cmd_use_sets_models():
  function test_cmd_use_reset (line 110) | def test_cmd_use_reset():
  function test_cmd_claude_md_missing (line 117) | def test_cmd_claude_md_missing(capsys):
  function test_cmd_stats_shows_tokens (line 125) | def test_cmd_stats_shows_tokens(capsys):
  function test_cmd_route_shows_tiers (line 133) | def test_cmd_route_shows_tiers(capsys):
  function test_cmd_help (line 141) | def test_cmd_help(capsys):
  function test_cmd_health (line 150) | def test_cmd_health(capsys):
  function test_dispatch_health (line 164) | def test_dispatch_health(capsys):
  function test_help_lists_health (line 176) | def test_help_lists_health(capsys):
  function test_models_empty_shows_known (line 183) | def test_models_empty_shows_known(capsys):
  function test_use_warns_unknown_model (line 194) | def test_use_warns_unknown_model(capsys):
  function test_budget_subscription_plan (line 202) | def test_budget_subscription_plan(capsys):
  function test_health_graceful_failure (line 215) | def test_health_graceful_failure(capsys):
  function test_stats_server_down (line 225) | def test_stats_server_down(capsys):

FILE: maggy/tests/test_rollback.py
  function _git (line 12) | def _git(repo, *args: str) -> None:
  function _init_repo (line 16) | def _init_repo(repo) -> None:
  class TestRollbackManager (line 25) | class TestRollbackManager:
    method test_create_and_list_savepoints (line 27) | async def test_create_and_list_savepoints(self, tmp_path):
    method test_rollback_resets_worktree (line 35) | async def test_rollback_resets_worktree(self, tmp_path):
    method test_delete_savepoint (line 44) | async def test_delete_savepoint(self, tmp_path):

FILE: maggy/tests/test_routes_escalation.py
  function _app (line 8) | def _app(tmp_path):
  function test_list_pending_empty (line 27) | def test_list_pending_empty(tmp_path):
  function test_create_and_list (line 34) | def test_create_and_list(tmp_path):
  function test_resolve_escalation (line 50) | def test_resolve_escalation(tmp_path):
  function test_resolve_not_found (line 71) | def test_resolve_not_found(tmp_path):

FILE: maggy/tests/test_routes_observability.py
  function _app (line 8) | def _app(tmp_path):
  function test_get_signals_empty (line 27) | def test_get_signals_empty(tmp_path):
  function test_record_and_read (line 34) | def test_record_and_read(tmp_path):

FILE: maggy/tests/test_routes_projects.py
  function _app (line 10) | def _app(mock_cfg):
  function test_list_projects_empty (line 22) | def test_list_projects_empty(mock_cfg):
  function test_add_and_list_project (line 29) | def test_add_and_list_project(mock_cfg):
  function test_get_project_not_found (line 45) | def test_get_project_not_found(mock_cfg):
  function test_add_duplicate_project (line 51) | def test_add_duplicate_project(mock_cfg):
  function test_delete_project (line 63) | def test_delete_project(mock_cfg):

FILE: maggy/tests/test_routing_config.py
  class TestStakesPatterns (line 14) | class TestStakesPatterns:
    method test_default_has_high_patterns (line 15) | def test_default_has_high_patterns(self):
    method test_default_has_medium_patterns (line 20) | def test_default_has_medium_patterns(self):
    method test_default_low_has_empty_patterns (line 25) | def test_default_low_has_empty_patterns(self):
  class TestCascadePolicy (line 30) | class TestCascadePolicy:
    method test_defaults (line 31) | def test_defaults(self):
    method test_custom_values (line 39) | def test_custom_values(self):
  class TestYamlRoundtrip (line 48) | class TestYamlRoundtrip:
    method test_roundtrip_preserves_stakes (line 49) | def test_roundtrip_preserves_stakes(self, tmp_path: Path):
    method test_roundtrip_preserves_cascade (line 56) | def test_roundtrip_preserves_cascade(self, tmp_path: Path):
    method test_roundtrip_preserves_conventions (line 63) | def test_roundtrip_preserves_conventions(self, tmp_path: Path):
    method test_user_edits_preserved (line 69) | def test_user_edits_preserved(self, tmp_path: Path):
    method test_missing_file_seeds_defaults (line 80) | def test_missing_file_seeds_defaults(self, tmp_path: Path):
  class TestToDict (line 87) | class TestToDict:
    method test_stakes_in_output (line 88) | def test_stakes_in_output(self):
    method test_cascade_in_output (line 94) | def test_cascade_in_output(self):
  class TestDefaultTiers (line 101) | class TestDefaultTiers:
    method test_no_gpt_in_defaults (line 104) | def test_no_gpt_in_defaults(self):
    method test_codex_is_primary (line 109) | def test_codex_is_primary(self):
    method test_codex_handles_complex (line 115) | def test_codex_handles_complex(self):
    method test_local_kimi_handle_simple (line 120) | def test_local_kimi_handle_simple(self):

FILE: maggy/tests/test_routing_rules.py
  function rules_path (line 22) | def rules_path(tmp_path: Path) -> Path:
  class TestDefaultRules (line 26) | class TestDefaultRules:
    method test_seeds_task_type_overrides (line 27) | def test_seeds_task_type_overrides(self):
    method test_seeds_pipeline_phases (line 33) | def test_seeds_pipeline_phases(self):
    method test_seeds_model_performance (line 39) | def test_seeds_model_performance(self):
  class TestLoadSave (line 45) | class TestLoadSave:
    method test_load_creates_default (line 46) | def test_load_creates_default(self, rules_path: Path):
    method test_roundtrip (line 51) | def test_roundtrip(self, rules_path: Path):
    method test_load_existing (line 60) | def test_load_existing(self, rules_path: Path):
  class TestApplyOverride (line 66) | class TestApplyOverride:
    method test_phase_takes_priority (line 67) | def test_phase_takes_priority(self):
    method test_auto_phase_returns_none (line 72) | def test_auto_phase_returns_none(self):
    method test_task_type_override (line 77) | def test_task_type_override(self):
    method test_no_override_returns_none (line 82) | def test_no_override_returns_none(self):
    method test_low_confidence_ignored (line 87) | def test_low_confidence_ignored(self):
  class TestRecordOutcome (line 97) | class TestRecordOutcome:
    method test_updates_success_rate (line 98) | def test_updates_success_rate(self, rules_path: Path):
    method test_creates_new_model (line 105) | def test_creates_new_model(self, rules_path: Path):
    method test_records_failure (line 111) | def test_records_failure(self, rules_path: Path):
  class TestLearnOverride (line 124) | class TestLearnOverride:
    method test_adds_new_override (line 125) | def test_adds_new_override(self, rules_path: Path):
    method test_persists_to_disk (line 135) | def test_persists_to_disk(self, rules_path: Path):

FILE: maggy/tests/test_routing_service.py
  class TestRoutingDecisions (line 9) | class TestRoutingDecisions:
    method test_low_complexity_routes_cheap (line 10) | def test_low_complexity_routes_cheap(self, mock_cfg):
    method test_high_complexity_routes_premium (line 21) | def test_high_complexity_routes_premium(self, mock_cfg):
    method test_security_sensitive_avoids_cheap (line 32) | def test_security_sensitive_avoids_cheap(self, mock_cfg):
  class TestRoutingLearning (line 48) | class TestRoutingLearning:
    method test_record_outcome (line 49) | def test_record_outcome(self, mock_cfg):
    method test_learned_override (line 55) | def test_learned_override(self, mock_cfg):
    method test_blast_tier_mapping (line 69) | def test_blast_tier_mapping(self, mock_cfg):

FILE: maggy/tests/test_scores.py
  class TestRewardRecord (line 8) | class TestRewardRecord:
    method test_record_and_heatmap (line 9) | def test_record_and_heatmap(self, mock_cfg):
    method test_multiple_records (line 16) | def test_multiple_records(self, mock_cfg):
  class TestBestModel (line 24) | class TestBestModel:
    method test_no_data_returns_none (line 25) | def test_no_data_returns_none(self, mock_cfg):
    method test_insufficient_samples_returns_none (line 29) | def test_insufficient_samples_returns_none(self, mock_cfg):
    method test_sufficient_samples_returns_best (line 35) | def test_sufficient_samples_returns_best(self, mock_cfg):
  class TestHeatmap (line 45) | class TestHeatmap:
    method test_empty_heatmap (line 46) | def test_empty_heatmap(self, mock_cfg):
    method test_heatmap_groups_correctly (line 50) | def test_heatmap_groups_correctly(self, mock_cfg):

FILE: maggy/tests/test_setup_routes.py
  function setup_app (line 21) | def setup_app(tmp_path: Path) -> FastAPI:
  function client (line 36) | def client(setup_app: FastAPI) -> TestClient:
  class TestSetupStatus (line 40) | class TestSetupStatus:
    method test_returns_steps (line 41) | def test_returns_steps(self, client: TestClient):
    method test_missing_token_detected (line 49) | def test_missing_token_detected(
    method test_progress_format (line 58) | def test_progress_format(self, client: TestClient):
    method test_configured_false_in_local (line 63) | def test_configured_false_in_local(
  class TestSetupConfigure (line 70) | class TestSetupConfigure:
    method test_updates_org (line 72) | def test_updates_org(self, mock_save, client):
    method test_updates_github_repos (line 82) | def test_updates_github_repos(
    method test_empty_body_is_noop (line 95) | def test_empty_body_is_noop(
  class TestDiscoverRepos (line 104) | class TestDiscoverRepos:
    method test_returns_repos (line 105) | def test_returns_repos(self, client: TestClient):

FILE: maggy/tests/test_stakes.py
  function _task (line 10) | def _task(title: str, desc: str = "", raw: dict | None = None) -> Task:
  class TestHighStakes (line 14) | class TestHighStakes:
    method test_auth_file_in_title (line 15) | def test_auth_file_in_title(self):
    method test_billing_task_type (line 19) | def test_billing_task_type(self):
    method test_security_task_type (line 24) | def test_security_task_type(self):
    method test_production_keyword_in_desc (line 29) | def test_production_keyword_in_desc(self):
    method test_env_file_pattern (line 34) | def test_env_file_pattern(self):
    method test_migration_in_title (line 38) | def test_migration_in_title(self):
  class TestMediumStakes (line 43) | class TestMediumStakes:
    method test_api_route_file (line 44) | def test_api_route_file(self):
    method test_feature_task_type (line 48) | def test_feature_task_type(self):
    method test_database_schema_change (line 53) | def test_database_schema_change(self):
  class TestLowStakes (line 58) | class TestLowStakes:
    method test_readme_update (line 59) | def test_readme_update(self):
    method test_docs_task_type (line 63) | def test_docs_task_type(self):
    method test_formatting_task (line 68) | def test_formatting_task(self):
  class TestStakesResult (line 74) | class TestStakesResult:
    method test_reasons_populated (line 75) | def test_reasons_populated(self):
    method test_custom_patterns (line 79) | def test_custom_patterns(self):

FILE: maggy/tests/test_tdd_verifier.py
  class TestParsers (line 14) | class TestParsers:
    method test_count_collected_normal (line 17) | def test_count_collected_normal(self):
    method test_count_collected_singular (line 20) | def test_count_collected_singular(self):
    method test_count_collected_missing (line 23) | def test_count_collected_missing(self):
    method test_count_failures_normal (line 26) | def test_count_failures_normal(self):
    method test_count_failures_none (line 29) | def test_count_failures_none(self):
    method test_parse_coverage_normal (line 32) | def test_parse_coverage_normal(self):
    method test_parse_coverage_missing (line 36) | def test_parse_coverage_missing(self):
  class TestVerifyResult (line 40) | class TestVerifyResult:
    method test_passed_result (line 43) | def test_passed_result(self):
    method test_failed_result (line 49) | def test_failed_result(self):
  class TestVerifyFunctions (line 56) | class TestVerifyFunctions:
    method test_verify_tests_exist_passes (line 60) | async def test_verify_tests_exist_passes(self, monkeypatch):
    method test_verify_tests_exist_fails (line 72) | async def test_verify_tests_exist_fails(self, monkeypatch):
    method test_verify_tests_fail_red (line 83) | async def test_verify_tests_fail_red(self, monkeypatch):
    method test_verify_tests_fail_rejects_pass (line 95) | async def test_verify_tests_fail_rejects_pass(self, monkeypatch):
    method test_verify_tests_pass_green (line 107) | async def test_verify_tests_pass_green(self, monkeypatch):
    method test_verify_lint_clean (line 118) | async def test_verify_lint_clean(self, monkeypatch):

FILE: maggy/tests/test_vision.py
  function png_file (line 15) | def png_file(tmp_path: Path) -> Path:
  function test_analyze_missing_file (line 28) | def test_analyze_missing_file():
  function test_analyze_bad_extension (line 34) | def test_analyze_bad_extension(tmp_path: Path):
  function test_analyze_streams_response (line 42) | def test_analyze_streams_response(png_file: Path):
  function test_analyze_with_custom_prompt (line 65) | def test_analyze_with_custom_prompt(png_file: Path):
  function test_analyze_ollama_down (line 89) | def test_analyze_ollama_down(png_file: Path):

FILE: maggy/tests/test_zero_config.py
  class TestHasProviderCredentials (line 17) | class TestHasProviderCredentials:
    method test_github_with_creds (line 18) | def test_github_with_creds(self):
    method test_github_no_token (line 27) | def test_github_no_token(self):
    method test_asana_with_creds (line 35) | def test_asana_with_creds(self):
    method test_linear_stub (line 43) | def test_linear_stub(self):
  class TestHasCliHistory (line 53) | class TestHasCliHistory:
    method test_claude_dir_exists (line 54) | def test_claude_dir_exists(self, tmp_path: Path):
    method test_no_dirs (line 59) | def test_no_dirs(self, tmp_path: Path):
    method test_codex_dir_exists (line 63) | def test_codex_dir_exists(self, tmp_path: Path):
  class TestAutoConfigure (line 72) | class TestAutoConfigure:
    method test_builds_config (line 73) | def test_builds_config(self, tmp_path: Path):
    method test_populates_codebases (line 81) | def test_populates_codebases(self, tmp_path: Path):
    method test_persist_writes_file (line 96) | def test_persist_writes_file(self, tmp_path: Path):
  class TestIsConfiguredRelaxed (line 111) | class TestIsConfiguredRelaxed:
    method test_false_without_anything (line 112) | def test_false_without_anything(self, tmp_path: Path):
    method test_true_with_cli_history (line 120) | def test_true_with_cli_history(self, tmp_path: Path):

FILE: scripts/icpg/__main__.py
  function main (line 21) | def main(argv: list[str] | None = None) -> int:
  function cmd_init (line 154) | def cmd_init(store: ICPGStore) -> int:
  function cmd_create (line 162) | def cmd_create(store: ICPGStore, args) -> int:
  function cmd_record (line 197) | def cmd_record(store: ICPGStore, args) -> int:
  function cmd_query (line 249) | def cmd_query(store: ICPGStore, args) -> int:
  function _resolve_path (line 268) | def _resolve_path(store: ICPGStore, file_path: str) -> str:
  function _query_context (line 276) | def _query_context(store: ICPGStore, file_path: str) -> int:
  function _query_blast (line 295) | def _query_blast(store: ICPGStore, reason_id: str) -> int:
  function _query_constraints (line 316) | def _query_constraints(store: ICPGStore, file_path: str) -> int:
  function _query_risk (line 334) | def _query_risk(store: ICPGStore, symbol_name: str) -> int:
  function _query_prior (line 355) | def _query_prior(store: ICPGStore, args) -> int:
  function cmd_drift (line 372) | def cmd_drift(store: ICPGStore, args) -> int:
  function _drift_scores (line 426) | def _drift_scores(event) -> list[float]:
  function cmd_bootstrap (line 437) | def cmd_bootstrap(store: ICPGStore, args) -> int:
  function cmd_status (line 458) | def cmd_status(store: ICPGStore) -> int:

FILE: scripts/icpg/bootstrap.py
  function bootstrap_from_git (line 24) | def bootstrap_from_git(
  function _get_commits (line 130) | def _get_commits(project_dir: Path, since: str) -> list[dict]:
  function _cluster_commits (line 187) | def _cluster_commits(
  function _infer_via_llm (line 222) | def _infer_via_llm(
  function _infer_from_messages (line 271) | def _infer_from_messages(
  function _parse_reason_response (line 306) | def _parse_reason_response(

FILE: scripts/icpg/contracts.py
  function infer_contracts (line 17) | def infer_contracts(
  function _infer_via_claude (line 41) | def _infer_via_claude(
  function _infer_via_openai (line 58) | def _infer_via_openai(
  function _infer_heuristic (line 78) | def _infer_heuristic(
  function _build_inference_prompt (line 106) | def _build_inference_prompt(
  function _parse_contract_response (line 140) | def _parse_contract_response(response: str) -> dict[str, list[str]]:
  function _empty_contracts (line 159) | def _empty_contracts() -> dict[str, list[str]]:
  function _guess_test_path (line 163) | def _guess_test_path(source_path: str) -> str | None:
  function format_contracts (line 181) | def format_contracts(reason: ReasonNode) -> str:

FILE: scripts/icpg/drift.py
  function check_file_drift (line 13) | def check_file_drift(store: ICPGStore, file_path: str) -> list[DriftEvent]:
  function check_all_drift (line 24) | def check_all_drift(store: ICPGStore) -> list[DriftEvent]:
  function check_symbol_drift (line 45) | def check_symbol_drift(
  function _check_spec_drift (line 117) | def _check_spec_drift(store, sym, reason) -> float | None:
  function _check_decision_drift (line 133) | def _check_decision_drift(store, reason) -> float | None:
  function _check_ownership_drift (line 148) | def _check_ownership_drift(store, sym) -> float | None:
  function _check_test_drift (line 162) | def _check_test_drift(store, reason) -> float | None:
  function _check_usage_drift (line 180) | def _check_usage_drift(store, sym, reason) -> float | None:
  function _check_dependency_drift (line 213) | def _check_dependency_drift(store, reason) -> float | None:
  function evaluate_predicate (line 230) | def evaluate_predicate(predicate: str, project_dir: Path) -> bool:
  function _match_predicate (line 265) | def _match_predicate(predicate: str, func_name: str) -> str | None:
  function _count_symbols_in_dir (line 271) | def _count_symbols_in_dir(dir_path: Path) -> int:
  function _compare (line 281) | def _compare(value: int, op: str, threshold: int) -> bool:

FILE: scripts/icpg/models.py
  function _now (line 11) | def _now() -> str:
  function _uuid (line 15) | def _uuid() -> str:
  function symbol_id (line 19) | def symbol_id(file_path: str, name: str, symbol_type: str) -> str:
  class ReasonNode (line 64) | class ReasonNode:
  class Symbol (line 86) | class Symbol:
    method __post_init__ (line 98) | def __post_init__(self):
  class Edge (line 104) | class Edge:
  class DriftEvent (line 116) | class DriftEvent:

FILE: scripts/icpg/store.py
  class ICPGStore (line 77) | class ICPGStore:
    method __init__ (line 80) | def __init__(self, project_dir: str = '.'):
    method init_db (line 85) | def init_db(self) -> None:
    method exists (line 94) | def exists(self) -> bool:
    method _conn (line 97) | def _conn(self) -> sqlite3.Connection:
    method create_reason (line 106) | def create_reason(self, node: ReasonNode) -> str:
    method get_reason (line 126) | def get_reason(self, reason_id: str) -> ReasonNode | None:
    method list_reasons (line 135) | def list_reasons(self, status: str | None = None) -> list[ReasonNode]:
    method update_reason_status (line 148) | def update_reason_status(
    method upsert_symbol (line 160) | def upsert_symbol(self, sym: Symbol) -> str:
    method get_symbols_for_file (line 177) | def get_symbols_for_file(self, file_path: str) -> list[Symbol]:
    method get_symbol_by_name (line 184) | def get_symbol_by_name(self, name: str) -> list[Symbol]:
    method create_edge (line 193) | def create_edge(self, edge: Edge) -> str:
    method get_edges_from (line 206) | def get_edges_from(
    method get_edges_to (line 221) | def get_edges_to(
    method create_drift_event (line 238) | def create_drift_event(self, event: DriftEvent) -> str:
    method get_unresolved_drift (line 253) | def get_unresolved_drift(self) -> list[DriftEvent]:
    method resolve_drift (line 261) | def resolve_drift(self, event_id: str) -> None:
    method get_reasons_for_file (line 270) | def get_reasons_for_file(self, file_path: str) -> list[ReasonNode]:
    method get_constraints_for_scope (line 283) | def get_constraints_for_scope(
    method get_blast_radius (line 302) | def get_blast_radius(self, reason_id: str) -> dict[str, Any]:
    method get_risk_profile (line 328) | def get_risk_profile(self, symbol_name: str) -> dict[str, Any]:
    method get_stats (line 363) | def get_stats(self) -> dict[str, int]:
    method _get_symbol (line 380) | def _get_symbol(self, symbol_id: str) -> Symbol | None:
    method _row_to_reason (line 388) | def _row_to_reason(row: sqlite3.Row) -> ReasonNode:
    method _row_to_symbol (line 408) | def _row_to_symbol(row: sqlite3.Row) -> Symbol:
    method _row_to_edge (line 421) | def _row_to_edge(row: sqlite3.Row) -> Edge:
    method _row_to_drift (line 432) | def _row_to_drift(row: sqlite3.Row) -> DriftEvent:

FILE: scripts/icpg/symbols.py
  function detect_language (line 36) | def detect_language(file_path: str) -> str | None:
  function checksum_content (line 41) | def checksum_content(content: str) -> str:
  function _extract_python (line 48) | def _extract_python(file_path: str, source: str) -> list[Symbol]:
  function _python_func_sig (line 88) | def _python_func_sig(node: ast.FunctionDef) -> str:
  function _python_class_sig (line 102) | def _python_class_sig(node: ast.ClassDef) -> str:
  function _extract_typescript (line 136) | def _extract_typescript(file_path: str, source: str) -> list[Symbol]:
  function _extract_go (line 174) | def _extract_go(file_path: str, source: str) -> list[Symbol]:
  function _extract_rust (line 210) | def _extract_rust(file_path: str, source: str) -> list[Symbol]:
  function _extract_elixir (line 245) | def _extract_elixir(file_path: str, source: str) -> list[Symbol]:
  function extract_symbols (line 282) | def extract_symbols(file_path: str) -> list[Symbol]:
  function extract_symbols_from_files (line 304) | def extract_symbols_from_files(file_paths: list[str]) -> list[Symbol]:

FILE: scripts/icpg/vectors.py
  class VectorStore (line 21) | class VectorStore:
    method __init__ (line 24) | def __init__(self, project_dir: str = '.'):
    method add_reason (line 29) | def add_reason(self, reason_id: str, goal: str, scope: list[str]) -> N...
    method search_similar (line 40) | def search_similar(
    method remove_reason (line 55) | def remove_reason(self, reason_id: str) -> None:
  function _detect_backend (line 65) | def _detect_backend() -> str:
  function _get_chroma_collection (line 86) | def _get_chroma_collection(icpg_dir: Path):
  function _chromadb_add (line 95) | def _chromadb_add(icpg_dir: Path, reason_id: str, text: str) -> None:
  function _chromadb_search (line 100) | def _chromadb_search(
  function _chromadb_remove (line 120) | def _chromadb_remove(icpg_dir: Path, reason_id: str) -> None:
  function _tfidf_load (line 130) | def _tfidf_load(icpg_dir: Path) -> dict[str, str]:
  function _tfidf_save (line 137) | def _tfidf_save(icpg_dir: Path, data: dict[str, str]) -> None:
  function _tfidf_add (line 142) | def _tfidf_add(icpg_dir: Path, reason_id: str, text: str) -> None:
  function _tfidf_search (line 148) | def _tfidf_search(
  function _tfidf_remove (line 178) | def _tfidf_remove(icpg_dir: Path, reason_id: str) -> None:
  function _exact_load (line 186) | def _exact_load(icpg_dir: Path) -> dict[str, str]:
  function _exact_save (line 193) | def _exact_save(icpg_dir: Path, data: dict[str, str]) -> None:
  function _exact_add (line 198) | def _exact_add(icpg_dir: Path, reason_id: str, text: str) -> None:
  function _exact_search (line 204) | def _exact_
Condensed preview — 501 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,095K chars).
[
  {
    "path": ".github/workflows/skill-lint.yml",
    "chars": 1088,
    "preview": "name: Skill Lint\n\non:\n  push:\n    branches: [main]\n    paths:\n      - 'skills/**'\n      - 'scripts/skill_lint/**'\n      "
  },
  {
    "path": ".github/workflows/skill-review.yml",
    "chars": 2513,
    "preview": "name: Skill Review (Tessl + skills-ref)\n\non:\n  pull_request:\n    paths:\n      - 'skills/**'\n\njobs:\n  tessl:\n    runs-on:"
  },
  {
    "path": ".gitignore",
    "chars": 54,
    "preview": "__pycache__/\n.DS_Store\nevals/.results/\n.pytest_cache/\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 61670,
    "preview": "# Changelog\n\nAll notable changes to Claude Bootstrap will be documented in this file.\n\nThe format is based on [Keep a Ch"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3648,
    "preview": "# Contributing to Maggy\n\nThanks for your interest in contributing! This project aims to make AI-assisted development mor"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2025 Ali Naqi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 36786,
    "preview": "# Maggy\n\n> **From opinionated Claude Code setup to autonomous AI engineering platform.**\n\nMaggy started as an opinionate"
  },
  {
    "path": "_project_specs/00-autonomous-engineering-roadmap.md",
    "chars": 2924,
    "preview": "# Autonomous Engineering Roadmap\n\nA set of specs closing the gaps between claude-bootstrap's current code-intelligence s"
  },
  {
    "path": "_project_specs/01-runtime-observability.md",
    "chars": 3425,
    "preview": "# Spec 01: Runtime Observability for Drift Detection\n\n**Status:** pending\n**Priority:** Tier 1 (highest leverage)\n**Effo"
  },
  {
    "path": "_project_specs/02-rollback-and-recovery.md",
    "chars": 3287,
    "preview": "# Spec 02: Rollback & Recovery\n\n**Status:** pending\n**Priority:** Tier 2\n**Effort:** Medium\n\n## Context\n\nWhen `iCPG` det"
  },
  {
    "path": "_project_specs/03-verifiable-contracts.md",
    "chars": 4211,
    "preview": "# Spec 03: Verifiable Contracts (Property-Based Test Generation)\n\n**Status:** pending\n**Priority:** Tier 1 (highest leve"
  },
  {
    "path": "_project_specs/04-multi-agent-coordination.md",
    "chars": 3915,
    "preview": "# Spec 04: Multi-Agent Coordination (Symbol-Level Locks)\n\n**Status:** pending\n**Priority:** Tier 2\n**Effort:** Medium\n\n#"
  },
  {
    "path": "_project_specs/05-confidence-calibration.md",
    "chars": 3812,
    "preview": "# Spec 05: Confidence Calibration (Reinforcement Loop)\n\n**Status:** pending\n**Priority:** Tier 3 (frontier)\n**Effort:** "
  },
  {
    "path": "_project_specs/06-cost-budget-awareness.md",
    "chars": 3229,
    "preview": "# Spec 06: Cost / Budget Awareness\n\n**Status:** pending\n**Priority:** Tier 3 (frontier)\n**Effort:** Small\n\n## Context\n\nA"
  },
  {
    "path": "_project_specs/07-human-escalation-protocol.md",
    "chars": 5025,
    "preview": "# Spec 07: Human-in-the-Loop Escalation Protocol\n\n**Status:** pending\n**Priority:** Tier 1 (highest leverage)\n**Effort:*"
  },
  {
    "path": "_project_specs/08-auto-code-index.md",
    "chars": 4512,
    "preview": "# Spec 08: Auto-Derived CODE_INDEX from Graph\n\n**Status:** pending\n**Priority:** Tier 2\n**Effort:** Small-Medium\n\n## Con"
  },
  {
    "path": "_project_specs/09-multimodal-ingestion.md",
    "chars": 5079,
    "preview": "# Spec 09: Multimodal Ingestion (Optional Graphify-Style Extension)\n\n**Status:** pending\n**Priority:** Tier 3 (frontier "
  },
  {
    "path": "commands/analyze-repo.md",
    "chars": 8274,
    "preview": "# Analyze Repository\n\nAnalyze an existing repository's structure, conventions, and guardrails.\n\n**This command runs auto"
  },
  {
    "path": "commands/analyze-workspace.md",
    "chars": 7490,
    "preview": "# /analyze-workspace\n\n> Full dynamic analysis of workspace topology, dependencies, and contracts.\n\n## Trigger\n\nRun this "
  },
  {
    "path": "commands/check-contributors.md",
    "chars": 5513,
    "preview": "# Check Contributors\n\nChecks who's working on the project and optionally converts to a multi-person project with team st"
  },
  {
    "path": "commands/icpg-bootstrap.md",
    "chars": 1401,
    "preview": "# /icpg-bootstrap — Bootstrap from Git History\n\nInfer ReasonNodes from existing git commit history. One-time setup for e"
  },
  {
    "path": "commands/icpg-drift.md",
    "chars": 1241,
    "preview": "# /icpg-drift — Show All Drift\n\nRun a full drift scan and display all unresolved drift events, grouped by dimension and "
  },
  {
    "path": "commands/icpg-impact.md",
    "chars": 1293,
    "preview": "# /icpg-impact — Show Blast Radius\n\nShow the blast radius of a ReasonNode or symbol — what depends on it, what breaks if"
  },
  {
    "path": "commands/icpg-why.md",
    "chars": 1200,
    "preview": "# /icpg-why — Why Does This Code Exist?\n\nTrace any symbol back to its creating ReasonNode — show the original goal, who "
  },
  {
    "path": "commands/initialize-project.md",
    "chars": 46629,
    "preview": "# Initialize Project\n\nFull project setup with Claude coding guardrails. Works for both new and existing projects.\n\n**Thi"
  },
  {
    "path": "commands/maggy-init.md",
    "chars": 3051,
    "preview": "# /maggy-init — Set Up Maggy for This Team\n\nInteractive wizard that configures Maggy for the user's org, issue tracker, "
  },
  {
    "path": "commands/maggy.md",
    "chars": 2237,
    "preview": "# /maggy — Launch Maggy Dashboard\n\nStart Maggy (the AI engineering command center) and open the dashboard in a browser.\n"
  },
  {
    "path": "commands/mnemos-checkpoint.md",
    "chars": 303,
    "preview": "# /mnemos-checkpoint — Write Mnemos Checkpoint\n\nWrite a checkpoint capturing current session state for later resume.\n\n##"
  },
  {
    "path": "commands/mnemos-status.md",
    "chars": 404,
    "preview": "# /mnemos-status — Show Mnemos Memory Status\n\nShow current Mnemos fatigue level, active node counts, and checkpoint stat"
  },
  {
    "path": "commands/polyphony-init.md",
    "chars": 1287,
    "preview": "# /polyphony-init — Setup Wizard\n\nInitialize the Polyphony multi-agent orchestration environment.\n\n---\n\n## Steps\n\n### 1."
  },
  {
    "path": "commands/polyphony-spawn.md",
    "chars": 868,
    "preview": "# /polyphony-spawn — Spawn Task\n\nCreate a new task in the Polyphony orchestrator and route it to an agent.\n\n---\n\n## Usag"
  },
  {
    "path": "commands/polyphony-status.md",
    "chars": 457,
    "preview": "# /polyphony-status — Show State\n\nDisplay the current state of all Polyphony tasks and running containers.\n\n---\n\n## Step"
  },
  {
    "path": "commands/spawn-team.md",
    "chars": 8192,
    "preview": "# /spawn-team - Spawn Agent Team\n\nSpawn the default agent team for this project. Creates a coordinated team of agents th"
  },
  {
    "path": "commands/sync-agents.md",
    "chars": 5623,
    "preview": "# Sync Agents\n\nSync project configuration between Claude Code, Kimi CLI, and Codex CLI.\n\nRun this after `/initialize-pro"
  },
  {
    "path": "commands/sync-contracts.md",
    "chars": 7373,
    "preview": "# /sync-contracts\n\n> Lightweight incremental update of workspace contracts without full re-analysis.\n\n## Purpose\n\nFast c"
  },
  {
    "path": "commands/update-code-index.md",
    "chars": 8277,
    "preview": "# Update Code Index\n\nRegenerates `CODE_INDEX.md` by scanning the codebase for all functions, classes, hooks, and compone"
  },
  {
    "path": "docs/architecture-v5.md",
    "chars": 154036,
    "preview": "# Maggy v5 Architecture — Multi-Project, Multi-Model Command Center\n\n## 1. Executive Summary\n\nv5 transforms Maggy from a"
  },
  {
    "path": "docs/benchmark-results.md",
    "chars": 15489,
    "preview": "# Maggy v5 Benchmark Results\n\n**Date:** 2026-05-11\n**App:** Personal Expense Tracker (FastAPI + SQLite + vanilla HTML/JS"
  },
  {
    "path": "docs/mnemos-implementation.md",
    "chars": 9509,
    "preview": "# Mnemos Implementation Addendum\n\nImplementation details for the Mnemos RFC (Task-Scoped Memory Lifecycle for Autonomous"
  },
  {
    "path": "docs/polyphony-spec.md",
    "chars": 5993,
    "preview": "# Polyphony v0.1 — Multi-Agent Orchestration Specification\n\n## Overview\n\nPolyphony is a container-isolated multi-agent o"
  },
  {
    "path": "evals/README.md",
    "chars": 2228,
    "preview": "# Behavioral Evals\n\nBehavioral evals test whether skills produce the expected coding patterns when loaded into Claude Co"
  },
  {
    "path": "evals/agent-teams/scenario-1/criteria.json",
    "chars": 525,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Pipeline ordering respected\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n  "
  },
  {
    "path": "evals/agent-teams/scenario-1/task.md",
    "chars": 301,
    "preview": "# Task: Build a REST API with Frontend\n\nCreate a full-stack feature:\n- Backend: FastAPI endpoint for managing bookmarks "
  },
  {
    "path": "evals/base/scenario-1/criteria.json",
    "chars": 891,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Functions under 50 lines\",\n      \"type\": \"deterministic\",\n      \"weight\": 1.0,\n  "
  },
  {
    "path": "evals/base/scenario-1/task.md",
    "chars": 302,
    "preview": "# Task: Build a URL Shortener Service\n\nCreate a Python URL shortener with these endpoints:\n- POST /shorten — accepts a U"
  },
  {
    "path": "evals/base/scenario-2/criteria.json",
    "chars": 610,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"TDD order followed\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n      \"prom"
  },
  {
    "path": "evals/base/scenario-2/task.md",
    "chars": 329,
    "preview": "# Task: Add Pagination to an Existing API\n\nYou have a FastAPI endpoint that returns all items from a database. Refactor "
  },
  {
    "path": "evals/code-review/scenario-1/criteria.json",
    "chars": 586,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Self-review performed\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n      \"p"
  },
  {
    "path": "evals/code-review/scenario-1/task.md",
    "chars": 323,
    "preview": "# Task: Implement a File Upload API\n\nCreate a FastAPI file upload endpoint:\n- Accept multipart file uploads up to 10MB\n-"
  },
  {
    "path": "evals/commit-hygiene/scenario-1/criteria.json",
    "chars": 518,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Atomic commits\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n      \"prompt\":"
  },
  {
    "path": "evals/commit-hygiene/scenario-1/task.md",
    "chars": 265,
    "preview": "# Task: Add Search and Sort to a Product List\n\nYou have an existing product listing page. Add:\n1. Search by product name"
  },
  {
    "path": "evals/credentials/scenario-1/criteria.json",
    "chars": 654,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Checks Access.txt or .env for keys\",\n      \"type\": \"llm_judged\",\n      \"weight\": "
  },
  {
    "path": "evals/credentials/scenario-1/task.md",
    "chars": 260,
    "preview": "# Task: Integrate Stripe Payment Processing\n\nAdd Stripe checkout to an existing e-commerce app:\n- Create checkout sessio"
  },
  {
    "path": "evals/database-schema/scenario-1/criteria.json",
    "chars": 619,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Schema read before writing queries\",\n      \"type\": \"llm_judged\",\n      \"weight\": "
  },
  {
    "path": "evals/database-schema/scenario-1/task.md",
    "chars": 252,
    "preview": "# Task: Add a Comments Feature to a Blog\n\nAn existing blog app has posts. Add comments:\n- Each comment belongs to a post"
  },
  {
    "path": "evals/existing-repo/scenario-1/criteria.json",
    "chars": 723,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Repo analyzed before changes\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n "
  },
  {
    "path": "evals/existing-repo/scenario-1/task.md",
    "chars": 288,
    "preview": "# Task: Add Dark Mode to an Existing React App\n\nAn existing React app needs dark mode support:\n- Toggle button in the he"
  },
  {
    "path": "evals/llm-patterns/scenario-1/criteria.json",
    "chars": 565,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Structured output used\",\n      \"type\": \"deterministic\",\n      \"weight\": 1.0,\n    "
  },
  {
    "path": "evals/llm-patterns/scenario-1/task.md",
    "chars": 317,
    "preview": "# Task: Build a Content Classifier\n\nCreate a Python service that:\n- Takes text input and classifies it into categories ("
  },
  {
    "path": "evals/project-tooling/scenario-1/criteria.json",
    "chars": 604,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"CLI tools verified\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n      \"prom"
  },
  {
    "path": "evals/project-tooling/scenario-1/task.md",
    "chars": 247,
    "preview": "# Task: Set Up a New Python Project\n\nInitialize a new Python project with:\n- pyproject.toml with dev dependencies\n- pyte"
  },
  {
    "path": "evals/python/scenario-1/criteria.json",
    "chars": 662,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Type hints on all public functions\",\n      \"type\": \"deterministic\",\n      \"weight"
  },
  {
    "path": "evals/python/scenario-1/task.md",
    "chars": 291,
    "preview": "# Task: Build a CSV Data Processor\n\nCreate a Python module that:\n- Reads CSV files with configurable delimiters\n- Valida"
  },
  {
    "path": "evals/react-web/scenario-1/criteria.json",
    "chars": 642,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Zustand store used\",\n      \"type\": \"deterministic\",\n      \"weight\": 1.0,\n      \"c"
  },
  {
    "path": "evals/react-web/scenario-1/task.md",
    "chars": 244,
    "preview": "# Task: Build a Todo App with Filters\n\nCreate a React todo app with:\n- Add/remove/toggle todos\n- Filter: all, active, co"
  },
  {
    "path": "evals/run-evals.sh",
    "chars": 2870,
    "preview": "#!/usr/bin/env bash\n# Run behavioral evals for Maggy skills.\n#\n# Usage:\n#   ./run-evals.sh                   # Run all e"
  },
  {
    "path": "evals/security/scenario-1/criteria.json",
    "chars": 832,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Password hashed with bcrypt or argon2\",\n      \"type\": \"deterministic\",\n      \"wei"
  },
  {
    "path": "evals/security/scenario-1/task.md",
    "chars": 244,
    "preview": "# Task: Build User Registration\n\nCreate a user registration endpoint:\n- Accept email and password\n- Store user in databa"
  },
  {
    "path": "evals/security/scenario-2/criteria.json",
    "chars": 659,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Keys not logged or exposed\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1.0,\n   "
  },
  {
    "path": "evals/security/scenario-2/task.md",
    "chars": 289,
    "preview": "# Task: Add API Key Authentication\n\nAdd API key authentication middleware to an existing FastAPI app:\n- Keys stored in d"
  },
  {
    "path": "evals/session-management/scenario-1/criteria.json",
    "chars": 475,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Session state checkpoint created\",\n      \"type\": \"llm_judged\",\n      \"weight\": 1."
  },
  {
    "path": "evals/session-management/scenario-1/task.md",
    "chars": 283,
    "preview": "# Task: Build a Multi-Step Form Wizard\n\nCreate a React multi-step form (3 steps: personal info, address, review) with:\n-"
  },
  {
    "path": "evals/supabase/scenario-1/criteria.json",
    "chars": 547,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"RLS policies created\",\n      \"type\": \"deterministic\",\n      \"weight\": 1.0,\n      "
  },
  {
    "path": "evals/supabase/scenario-1/task.md",
    "chars": 293,
    "preview": "# Task: Build a User Profile System\n\nCreate a Supabase-backed user profile system:\n- profiles table linked to auth.users"
  },
  {
    "path": "evals/typescript/scenario-1/criteria.json",
    "chars": 571,
    "preview": "{\n  \"criteria\": [\n    {\n      \"name\": \"Strict TypeScript mode\",\n      \"type\": \"deterministic\",\n      \"weight\": 1.0,\n    "
  },
  {
    "path": "evals/typescript/scenario-1/task.md",
    "chars": 326,
    "preview": "# Task: Build a Task Queue Library\n\nCreate a TypeScript task queue that:\n- Accepts async functions with priority levels\n"
  },
  {
    "path": "hooks/post-commit-graph",
    "chars": 1474,
    "preview": "#!/bin/bash\n\n# Post-Commit Graph Update Hook\n#\n# Triggers incremental codebase-memory-mcp graph update after each commit"
  },
  {
    "path": "hooks/pre-push",
    "chars": 4020,
    "preview": "#!/bin/bash\n\n# Claude Code Review - Pre-Push Hook\n# Runs /code-review on changes before pushing to remote\n# Blocks push "
  },
  {
    "path": "hooks/workspace/check-contract-freshness.sh",
    "chars": 2285,
    "preview": "#!/bin/bash\n\n# Contract Freshness Check - Session Start Hook\n# Checks if workspace contracts are stale and advises user\n"
  },
  {
    "path": "hooks/workspace/check-graph-freshness.sh",
    "chars": 1714,
    "preview": "#!/bin/bash\n\n# Check Graph Freshness - Session Start Advisory\n#\n# Warns if code graph data is older than the latest comm"
  },
  {
    "path": "hooks/workspace/post-commit-contracts.sh",
    "chars": 1870,
    "preview": "#!/bin/bash\n\n# Post-Commit Contract Sync Hook\n# Automatically syncs contracts when contract source files are committed\n#"
  },
  {
    "path": "hooks/workspace/pre-push-contracts.sh",
    "chars": 2986,
    "preview": "#!/bin/bash\n\n# Pre-Push Contract Validation Hook\n# Validates contract consistency before pushing\n# Blocks push if contra"
  },
  {
    "path": "install.sh",
    "chars": 7930,
    "preview": "#!/bin/bash\n\n# Maggy Installer\n\nset -e\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nCLAUDE_DIR=\"$HOME/.cl"
  },
  {
    "path": "maggy/.gitignore",
    "chars": 87,
    "preview": "__pycache__/\n*.py[cod]\n*$py.class\n.pytest_cache/\n.mypy_cache/\n.ruff_cache/\n*.egg-info/\n"
  },
  {
    "path": "maggy/PLAN.md",
    "chars": 7318,
    "preview": "# Maggy — Generic AI Engineering Command Center\n\nShips as a core component of Maggy. One install, works with any team.\n\n"
  },
  {
    "path": "maggy/README.md",
    "chars": 4366,
    "preview": "# Maggy\n\n**Autonomous AI engineering command center.**\n\nInstall once, point it at your codebases and issue tracker, and "
  },
  {
    "path": "maggy/config.example.yaml",
    "chars": 2542,
    "preview": "# Maggy configuration\n# Copy this to ~/.maggy/config.yaml and customize.\n\norg:\n  name: \"Your Org\"\n  # Drives competitor "
  },
  {
    "path": "maggy/docs/benchmark-results.md",
    "chars": 17379,
    "preview": "# Maggy v5 Benchmark Results\n\n**Date:** 2026-05-11\n**App:** Personal Expense Tracker (FastAPI + SQLite + vanilla HTML/JS"
  },
  {
    "path": "maggy/docs/maggy-rfc.md",
    "chars": 53484,
    "preview": "# Maggy: An Autonomous AI Engineering Platform\n\n**RFC — Request for Comments**\n**Author:** Ali Shaheen, Protaige\n**Date:"
  },
  {
    "path": "maggy/install.sh",
    "chars": 3209,
    "preview": "#!/usr/bin/env bash\n# Maggy installer — sets up deps and copies config template.\n#\n# Usage: ./install.sh\n\nset -euo pipef"
  },
  {
    "path": "maggy/maggy/__init__.py",
    "chars": 76,
    "preview": "\"\"\"Maggy — generic AI engineering command center.\"\"\"\n\n__version__ = \"0.1.0\"\n"
  },
  {
    "path": "maggy/maggy/adapters/__init__.py",
    "chars": 56,
    "preview": "\"\"\"Unified agent adapters for multi-model execution.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/adapters/cli_discovery.py",
    "chars": 9028,
    "preview": "\"\"\"Auto-discover installed AI CLIs and their command-line flags.\n\nProbes each CLI via --help, parses capabilities, and b"
  },
  {
    "path": "maggy/maggy/adapters/pi.py",
    "chars": 8611,
    "preview": "\"\"\"Unified adapter for CLI prompts and Pi RPC control.\n\nAuto-discovers installed AI CLIs and their flags at init time\nso"
  },
  {
    "path": "maggy/maggy/api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "maggy/maggy/api/auth.py",
    "chars": 1200,
    "preview": "\"\"\"Shared authentication and configuration guards.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import HTTPExcep"
  },
  {
    "path": "maggy/maggy/api/routes.py",
    "chars": 9586,
    "preview": "\"\"\"REST API routes — wraps services. All routes under /api/*.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfro"
  },
  {
    "path": "maggy/maggy/api/routes_budget.py",
    "chars": 847,
    "preview": "\"\"\"Budget REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, Request\n\nfrom ."
  },
  {
    "path": "maggy/maggy/api/routes_chat.py",
    "chars": 8594,
    "preview": "\"\"\"Chat API routes — interactive Claude sessions via SSE.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport log"
  },
  {
    "path": "maggy/maggy/api/routes_cikg.py",
    "chars": 1053,
    "preview": "\"\"\"CIKG REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, Request\n\nfrom .au"
  },
  {
    "path": "maggy/maggy/api/routes_deploy.py",
    "chars": 1720,
    "preview": "\"\"\"Deploy REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfrom fastapi import AP"
  },
  {
    "path": "maggy/maggy/api/routes_engram.py",
    "chars": 1247,
    "preview": "\"\"\"Engram REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfrom fastapi import AP"
  },
  {
    "path": "maggy/maggy/api/routes_escalation.py",
    "chars": 1899,
    "preview": "\"\"\"Escalation REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, HTTPExcepti"
  },
  {
    "path": "maggy/maggy/api/routes_events.py",
    "chars": 1437,
    "preview": "\"\"\"Event Spine REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, Request\n\nf"
  },
  {
    "path": "maggy/maggy/api/routes_forge.py",
    "chars": 1762,
    "preview": "\"\"\"Forge REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfrom fastapi import API"
  },
  {
    "path": "maggy/maggy/api/routes_heartbeat.py",
    "chars": 1094,
    "preview": "\"\"\"Heartbeat API routes — scheduler status and manual triggers.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi imp"
  },
  {
    "path": "maggy/maggy/api/routes_history.py",
    "chars": 2021,
    "preview": "\"\"\"API routes for session history analysis.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Heade"
  },
  {
    "path": "maggy/maggy/api/routes_improve.py",
    "chars": 1150,
    "preview": "\"\"\"Self-improvement API routes — reports and manual analysis.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses i"
  },
  {
    "path": "maggy/maggy/api/routes_lexon.py",
    "chars": 1208,
    "preview": "\"\"\"Lexon REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfrom fastapi import API"
  },
  {
    "path": "maggy/maggy/api/routes_mesh.py",
    "chars": 4466,
    "preview": "\"\"\"Mesh P2P REST endpoints — data operations.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfr"
  },
  {
    "path": "maggy/maggy/api/routes_mesh_admin.py",
    "chars": 2150,
    "preview": "\"\"\"Mesh P2P REST endpoints — admin operations.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, He"
  },
  {
    "path": "maggy/maggy/api/routes_monitor.py",
    "chars": 1064,
    "preview": "\"\"\"API routes for monitor service — tracker polling.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRout"
  },
  {
    "path": "maggy/maggy/api/routes_observability.py",
    "chars": 1208,
    "preview": "\"\"\"Observability signal REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, H"
  },
  {
    "path": "maggy/maggy/api/routes_planning.py",
    "chars": 1208,
    "preview": "\"\"\"Planning REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import asdict\n\nfrom fastapi import "
  },
  {
    "path": "maggy/maggy/api/routes_process.py",
    "chars": 2460,
    "preview": "\"\"\"Process Intelligence REST routes — /api/process/*.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\n\nfrom fasta"
  },
  {
    "path": "maggy/maggy/api/routes_projects.py",
    "chars": 2461,
    "preview": "\"\"\"Project registry REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, HTTPE"
  },
  {
    "path": "maggy/maggy/api/routes_routing.py",
    "chars": 2033,
    "preview": "\"\"\"Routing REST endpoints.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastapi import APIRouter, Header, Request\n\nfrom "
  },
  {
    "path": "maggy/maggy/api/routes_setup.py",
    "chars": 4948,
    "preview": "\"\"\"Setup and onboarding routes — detect missing config, guide users.\"\"\"\n\nfrom __future__ import annotations\n\nfrom fastap"
  },
  {
    "path": "maggy/maggy/budget.py",
    "chars": 6512,
    "preview": "\"\"\"Token budget manager — tracks spend per provider with daily limits.\"\"\"\n\nfrom __future__ import annotations\n\nimport sq"
  },
  {
    "path": "maggy/maggy/calibration/__init__.py",
    "chars": 102,
    "preview": "\"\"\"Calibration exports.\"\"\"\n\nfrom .tracker import CalibrationTracker\n\n__all__ = [\"CalibrationTracker\"]\n"
  },
  {
    "path": "maggy/maggy/calibration/tracker.py",
    "chars": 2141,
    "preview": "\"\"\"SQLite-backed model calibration tracking.\"\"\"\n\nfrom __future__ import annotations\n\nimport sqlite3\nfrom contextlib impo"
  },
  {
    "path": "maggy/maggy/checkpoint.py",
    "chars": 2222,
    "preview": "\"\"\"JSON checkpoint persistence for fallback chains.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nfrom pathlib imp"
  },
  {
    "path": "maggy/maggy/cikg/__init__.py",
    "chars": 48,
    "preview": "\"\"\"Competitive Intelligence Knowledge Graph.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/cikg/graph.py",
    "chars": 3714,
    "preview": "\"\"\"KnowledgeGraphService — CRUD operations for CIKG.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport sqlite3\n"
  },
  {
    "path": "maggy/maggy/cikg/models.py",
    "chars": 1468,
    "preview": "\"\"\"CIKG node and edge models.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, field\nfrom date"
  },
  {
    "path": "maggy/maggy/cikg/queries.py",
    "chars": 5127,
    "preview": "\"\"\"CIKG query functions — gap analysis and market scoring.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .graph import Kn"
  },
  {
    "path": "maggy/maggy/cikg/storage.py",
    "chars": 1272,
    "preview": "\"\"\"SQLite helpers for the competitive graph.\"\"\"\n\nfrom __future__ import annotations\n\nimport sqlite3\nfrom contextlib impo"
  },
  {
    "path": "maggy/maggy/cli.py",
    "chars": 5615,
    "preview": "\"\"\"Maggy CLI — terminal interface for the engineering platform.\"\"\"\n\nfrom __future__ import annotations\n\nimport typer\n\nfr"
  },
  {
    "path": "maggy/maggy/cli_chat.py",
    "chars": 6781,
    "preview": "\"\"\"Interactive chat REPL for Maggy CLI with model routing.\"\"\"\nfrom __future__ import annotations\n\nimport os\n\nfrom rich.c"
  },
  {
    "path": "maggy/maggy/cli_client.py",
    "chars": 8614,
    "preview": "\"\"\"HTTP client for Maggy REST API.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport os\nimport signal\nimport su"
  },
  {
    "path": "maggy/maggy/cli_output.py",
    "chars": 5549,
    "preview": "\"\"\"Rich terminal formatters for Maggy CLI output.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport sys\n\nfrom r"
  },
  {
    "path": "maggy/maggy/cli_repl_cmds.py",
    "chars": 7419,
    "preview": "\"\"\"REPL slash command handlers for Maggy CLI.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass,"
  },
  {
    "path": "maggy/maggy/cli_sessions.py",
    "chars": 1321,
    "preview": "\"\"\"Session management for Maggy CLI — spawn, list, kill.\"\"\"\n\nfrom __future__ import annotations\n\nfrom rich.console impor"
  },
  {
    "path": "maggy/maggy/cli_welcome.py",
    "chars": 2859,
    "preview": "\"\"\"Rich welcome banner for Maggy CLI startup.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\n\nfrom rich.console impor"
  },
  {
    "path": "maggy/maggy/config.py",
    "chars": 12048,
    "preview": "\"\"\"Config loader for Maggy — reads ~/.maggy/config.yaml with env overrides.\"\"\"\n\nfrom __future__ import annotations\n\nimpo"
  },
  {
    "path": "maggy/maggy/contracts/__init__.py",
    "chars": 100,
    "preview": "\"\"\"Contracts exports.\"\"\"\n\nfrom .generator import ContractGenerator\n\n__all__ = [\"ContractGenerator\"]\n"
  },
  {
    "path": "maggy/maggy/contracts/generator.py",
    "chars": 705,
    "preview": "\"\"\"Generate lightweight contract tests from postconditions.\"\"\"\n\nfrom __future__ import annotations\n\nimport re\n\n\nclass Co"
  },
  {
    "path": "maggy/maggy/coordination/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "maggy/maggy/coordination/lock_manager.py",
    "chars": 3837,
    "preview": "\"\"\"SQLite-backed file locks for multi-agent coordination.\"\"\"\n\nfrom __future__ import annotations\n\nimport sqlite3\nfrom co"
  },
  {
    "path": "maggy/maggy/deploy.py",
    "chars": 1994,
    "preview": "\"\"\"Deploy orchestrator — manages Vercel session containers.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom "
  },
  {
    "path": "maggy/maggy/discovery.py",
    "chars": 6921,
    "preview": "\"\"\"Auto-discovery — detects local CLIs, repos, and dev environment.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\n"
  },
  {
    "path": "maggy/maggy/engram/__init__.py",
    "chars": 48,
    "preview": "\"\"\"Engram — cross-session persistent memory.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/engram/diagnostics.py",
    "chars": 1697,
    "preview": "\"\"\"AmnesiaProfile — 7-dimension memory diagnostics.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import data"
  },
  {
    "path": "maggy/maggy/engram/record.py",
    "chars": 1091,
    "preview": "\"\"\"EngramRecord — the unit of persistent memory.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import datacla"
  },
  {
    "path": "maggy/maggy/engram/retrieval.py",
    "chars": 1802,
    "preview": "\"\"\"Multi-path retrieval for Engram records.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .record import EngramRecord\nfro"
  },
  {
    "path": "maggy/maggy/engram/seed.py",
    "chars": 1521,
    "preview": "\"\"\"Seed engrams on first boot for non-zero health.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .record import EngramRec"
  },
  {
    "path": "maggy/maggy/engram/store.py",
    "chars": 4586,
    "preview": "\"\"\"SQLite store for Engram records with namespace isolation.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport "
  },
  {
    "path": "maggy/maggy/escalation/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "maggy/maggy/escalation/protocol.py",
    "chars": 4980,
    "preview": "\"\"\"Human escalation packets with SQLite persistence.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport sqlite3\n"
  },
  {
    "path": "maggy/maggy/event_spine/__init__.py",
    "chars": 175,
    "preview": "\"\"\"Event Spine — canonical event flow for end-to-end tracing.\"\"\"\n\nfrom .emitter import EventEmitter\nfrom .header import "
  },
  {
    "path": "maggy/maggy/event_spine/emitter.py",
    "chars": 1741,
    "preview": "\"\"\"Event emitter — write, query, and trace events.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom dataclass"
  },
  {
    "path": "maggy/maggy/event_spine/events.py",
    "chars": 2869,
    "preview": "\"\"\"Eight typed event dataclasses for the Event Spine.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import da"
  },
  {
    "path": "maggy/maggy/event_spine/header.py",
    "chars": 774,
    "preview": "\"\"\"Common EventHeader shared by all typed events.\"\"\"\n\nfrom __future__ import annotations\n\nimport uuid\nfrom dataclasses i"
  },
  {
    "path": "maggy/maggy/event_spine/store.py",
    "chars": 5367,
    "preview": "\"\"\"SQLite event store — append-only with archive support.\"\"\"\n\nfrom __future__ import annotations\n\nimport gzip\nimport jso"
  },
  {
    "path": "maggy/maggy/fatigue.py",
    "chars": 2112,
    "preview": "\"\"\"Model-normalized fatigue tracking for cross-model sessions.\n\nNormalizes fatigue scores across models with different c"
  },
  {
    "path": "maggy/maggy/forge/__init__.py",
    "chars": 60,
    "preview": "\"\"\"MCP Forge integration — bridge to mcp-forge pipeline.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/forge/connector.py",
    "chars": 2610,
    "preview": "\"\"\"Bridge to mcp-forge — wraps registry, pipeline, codegen.\n\nConnects Maggy to the MCP Forge at ~/Documents/protaige/mcp"
  },
  {
    "path": "maggy/maggy/forge/detector.py",
    "chars": 1774,
    "preview": "\"\"\"Capability gap detection — monitors unresolvable requests.\n\nTracks patterns of failed tool lookups and triggers Forge"
  },
  {
    "path": "maggy/maggy/forge/registry.py",
    "chars": 2639,
    "preview": "\"\"\"Tool registry — wraps mcp-forge's KNOWN_SERVERS.\n\nProvides enable/disable per project and search capabilities\nwithout"
  },
  {
    "path": "maggy/maggy/heartbeat/__init__.py",
    "chars": 58,
    "preview": "\"\"\"Heartbeat — background scheduler for periodic jobs.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/heartbeat/jobs.py",
    "chars": 2840,
    "preview": "\"\"\"Built-in heartbeat jobs — wire to existing services.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom date"
  },
  {
    "path": "maggy/maggy/heartbeat/scheduler.py",
    "chars": 2938,
    "preview": "\"\"\"Core heartbeat scheduler — register and run periodic jobs.\"\"\"\n\nfrom __future__ import annotations\n\nimport asyncio\nimp"
  },
  {
    "path": "maggy/maggy/history/__init__.py",
    "chars": 70,
    "preview": "\"\"\"Session history analyzer — reads Claude/Codex/Kimi local state.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/history/analyzer.py",
    "chars": 5785,
    "preview": "\"\"\"Aggregation and pattern detection for session history.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections impor"
  },
  {
    "path": "maggy/maggy/history/models.py",
    "chars": 2413,
    "preview": "\"\"\"Data models for session history analysis.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, "
  },
  {
    "path": "maggy/maggy/history/parsers/__init__.py",
    "chars": 272,
    "preview": "\"\"\"History parsers for Claude Code, Codex CLI, and Kimi CLI.\"\"\"\n\nfrom .claude import ClaudeHistoryParser\nfrom .codex imp"
  },
  {
    "path": "maggy/maggy/history/parsers/base.py",
    "chars": 691,
    "preview": "\"\"\"Abstract base for CLI history parsers.\"\"\"\n\nfrom __future__ import annotations\n\nfrom abc import ABC, abstractmethod\n\nf"
  },
  {
    "path": "maggy/maggy/history/parsers/claude.py",
    "chars": 5883,
    "preview": "\"\"\"Claude Code history parser — reads ~/.claude/ local state.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport"
  },
  {
    "path": "maggy/maggy/history/parsers/codex.py",
    "chars": 3926,
    "preview": "\"\"\"Codex CLI history parser — reads ~/.codex/ local state.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport lo"
  },
  {
    "path": "maggy/maggy/history/parsers/kimi.py",
    "chars": 4676,
    "preview": "\"\"\"Kimi CLI history parser — reads ~/.kimi/ local state.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport logg"
  },
  {
    "path": "maggy/maggy/history/service.py",
    "chars": 2860,
    "preview": "\"\"\"History analysis service — orchestrates the full pipeline.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfro"
  },
  {
    "path": "maggy/maggy/history/store.py",
    "chars": 5038,
    "preview": "\"\"\"SQLite store for session history data.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport sqlite3\nfrom contex"
  },
  {
    "path": "maggy/maggy/improve/__init__.py",
    "chars": 57,
    "preview": "\"\"\"Self-improvement — signal collection and analysis.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/improve/analyzer.py",
    "chars": 3939,
    "preview": "\"\"\"Analyze collected signals and produce recommendations.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .models import Re"
  },
  {
    "path": "maggy/maggy/improve/models.py",
    "chars": 981,
    "preview": "\"\"\"Data models for self-improvement analysis.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass,"
  },
  {
    "path": "maggy/maggy/improve/service.py",
    "chars": 3906,
    "preview": "\"\"\"Introspector — orchestrates signal collection and analysis.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfr"
  },
  {
    "path": "maggy/maggy/improve/signals.py",
    "chars": 2761,
    "preview": "\"\"\"Signal collectors — pull data from existing services.\"\"\"\n\nfrom __future__ import annotations\n\nfrom datetime import da"
  },
  {
    "path": "maggy/maggy/lexon/__init__.py",
    "chars": 54,
    "preview": "\"\"\"Lexon — intent parsing and tool disambiguation.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/lexon/disambiguate.py",
    "chars": 1447,
    "preview": "\"\"\"Confidence-gated disambiguation for ambiguous intents.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses impor"
  },
  {
    "path": "maggy/maggy/lexon/personalization.py",
    "chars": 2028,
    "preview": "\"\"\"Implicit learning — tracks 5 user behavior signals.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections import C"
  },
  {
    "path": "maggy/maggy/lexon/record.py",
    "chars": 761,
    "preview": "\"\"\"LexonRecord — parsed intent with confidence.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclas"
  },
  {
    "path": "maggy/maggy/lexon/router.py",
    "chars": 3953,
    "preview": "\"\"\"Two-tier Lexon router — fast keyword + fallback LLM.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .disambiguate impor"
  },
  {
    "path": "maggy/maggy/lexon/terminology.py",
    "chars": 2471,
    "preview": "\"\"\"3-level terminology map for intent normalization.\n\nLevel 1: Canonical terms (e.g., \"deploy\")\nLevel 2: Synonyms (e.g.,"
  },
  {
    "path": "maggy/maggy/main.py",
    "chars": 13778,
    "preview": "\"\"\"Maggy FastAPI app entrypoint.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom contextlib import asynccont"
  },
  {
    "path": "maggy/maggy/mesh/__init__.py",
    "chars": 57,
    "preview": "\"\"\"Maggy Mesh — P2P memory sharing between instances.\"\"\"\n"
  },
  {
    "path": "maggy/maggy/mesh/discovery.py",
    "chars": 2403,
    "preview": "\"\"\"Peer discovery — registry with optional SQLite backing.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses impo"
  },
  {
    "path": "maggy/maggy/mesh/git_discovery.py",
    "chars": 4810,
    "preview": "\"\"\"Git-based peer discovery via GitHub Contents API.\"\"\"\n\nfrom __future__ import annotations\n\nimport base64\nimport json\ni"
  },
  {
    "path": "maggy/maggy/mesh/manager.py",
    "chars": 2888,
    "preview": "\"\"\"MeshManager — orchestrates multiple org networks.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport platf"
  },
  {
    "path": "maggy/maggy/mesh/memory.py",
    "chars": 733,
    "preview": "\"\"\"Typed memory categories for Mesh sharing.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, "
  },
  {
    "path": "maggy/maggy/mesh/network.py",
    "chars": 1163,
    "preview": "\"\"\"Network — one isolated mesh per GitHub org.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom dataclasses i"
  },
  {
    "path": "maggy/maggy/mesh/org_scanner.py",
    "chars": 764,
    "preview": "\"\"\"Scan local repos for unique GitHub org names.\"\"\"\n\nfrom __future__ import annotations\n\nfrom pathlib import Path\n\nfrom "
  },
  {
    "path": "maggy/maggy/mesh/protocol.py",
    "chars": 1407,
    "preview": "\"\"\"Message types and serialization for Mesh protocol.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nfrom dataclass"
  },
  {
    "path": "maggy/maggy/mesh/provenance.py",
    "chars": 924,
    "preview": "\"\"\"Provenance tracking with confidence decay.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass,"
  },
  {
    "path": "maggy/maggy/mesh/publisher.py",
    "chars": 2240,
    "preview": "\"\"\"Collect local data and build shareable memories.\"\"\"\n\nfrom __future__ import annotations\n\nfrom .memory import SharedMe"
  },
  {
    "path": "maggy/maggy/mesh/quarantine.py",
    "chars": 2569,
    "preview": "\"\"\"Quarantine system for untrusted mesh data.\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass,"
  },
  {
    "path": "maggy/maggy/mesh/store.py",
    "chars": 5354,
    "preview": "\"\"\"SQLite backing for mesh peers, memories, and quarantine.\"\"\"\n\nfrom __future__ import annotations\n\nimport json\nimport s"
  },
  {
    "path": "maggy/maggy/mesh/sync.py",
    "chars": 2892,
    "preview": "\"\"\"Sync engine — merges shared memories across peers.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom datacl"
  },
  {
    "path": "maggy/maggy/mesh/transport.py",
    "chars": 1796,
    "preview": "\"\"\"Transport layer — HMAC auth and org key derivation.\"\"\"\n\nfrom __future__ import annotations\n\nimport hashlib\nimport hma"
  },
  {
    "path": "maggy/maggy/mesh/ws_client.py",
    "chars": 2851,
    "preview": "\"\"\"Async WebSocket client for mesh peer connections.\"\"\"\n\nfrom __future__ import annotations\n\nimport asyncio\nimport loggi"
  },
  {
    "path": "maggy/maggy/mesh/ws_server.py",
    "chars": 3697,
    "preview": "\"\"\"WebSocket server endpoint for mesh communication.\"\"\"\n\nfrom __future__ import annotations\n\nimport asyncio\nimport json\n"
  }
]

// ... and 301 more files (download for full content)

About this extraction

This page contains the full source code of the alinaqi/claude-bootstrap GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 501 files (2.7 MB), approximately 735.9k tokens, and a symbol index with 2970 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!