@jaguilar87/gaia-ops 4.4.0 → 4.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +12 -3
- package/ARCHITECTURE.md +9 -8
- package/CHANGELOG.md +34 -0
- package/README.md +43 -11
- package/agents/terraform-architect.md +1 -1
- package/bin/README.md +2 -2
- package/bin/gaia-doctor.js +18 -5
- package/bin/gaia-history.js +0 -1
- package/bin/gaia-metrics.js +2 -2
- package/bin/gaia-scan.py +23 -1
- package/bin/gaia-update.js +346 -54
- package/bin/pre-publish-validate.js +33 -10
- package/commands/gaia.md +37 -0
- package/config/README.md +3 -9
- package/config/context-contracts.json +47 -15
- package/config/surface-routing.json +9 -1
- package/dist/gaia-ops/.claude-plugin/plugin.json +22 -0
- package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
- package/dist/gaia-ops/agents/devops-developer.md +57 -0
- package/dist/gaia-ops/agents/gaia-system.md +58 -0
- package/dist/gaia-ops/agents/gitops-operator.md +60 -0
- package/dist/gaia-ops/agents/speckit-planner.md +71 -0
- package/dist/gaia-ops/agents/terraform-architect.md +60 -0
- package/dist/gaia-ops/commands/gaia.md +37 -0
- package/dist/gaia-ops/config/README.md +58 -0
- package/dist/gaia-ops/config/cloud/aws.json +140 -0
- package/dist/gaia-ops/config/cloud/gcp.json +145 -0
- package/dist/gaia-ops/config/context-contracts.json +131 -0
- package/dist/gaia-ops/config/git_standards.json +72 -0
- package/dist/gaia-ops/config/surface-routing.json +197 -0
- package/dist/gaia-ops/config/universal-rules.json +10 -0
- package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-ops/hooks/adapters/base.py +219 -0
- package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
- package/dist/gaia-ops/hooks/adapters/claude_code.py +1477 -0
- package/dist/gaia-ops/hooks/adapters/types.py +194 -0
- package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
- package/dist/gaia-ops/hooks/hooks.json +126 -0
- package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
- package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +124 -0
- package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +576 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +215 -0
- package/dist/gaia-ops/hooks/modules/context/context_cache.py +129 -0
- package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-ops/hooks/modules/context/context_injector.py +427 -0
- package/dist/gaia-ops/hooks/modules/context/context_writer.py +518 -0
- package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +558 -0
- package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
- package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-ops/hooks/modules/identity/__init__.py +0 -0
- package/dist/gaia-ops/hooks/modules/identity/identity_provider.py +21 -0
- package/dist/gaia-ops/hooks/modules/identity/ops_identity.py +34 -0
- package/dist/gaia-ops/hooks/modules/identity/security_identity.py +10 -0
- package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +227 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +128 -0
- package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-ops/hooks/modules/security/__init__.py +89 -0
- package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-ops/hooks/modules/security/approval_grants.py +912 -0
- package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +153 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +584 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +86 -0
- package/dist/gaia-ops/hooks/modules/security/command_semantics.py +130 -0
- package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +850 -0
- package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +158 -0
- package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-ops/hooks/modules/tools/__init__.py +25 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +708 -0
- package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +181 -0
- package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-ops/hooks/modules/tools/task_validator.py +283 -0
- package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-ops/hooks/post_compact.py +43 -0
- package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
- package/dist/gaia-ops/hooks/pre_tool_use.py +383 -0
- package/dist/gaia-ops/hooks/session_start.py +69 -0
- package/dist/gaia-ops/hooks/stop_hook.py +69 -0
- package/dist/gaia-ops/hooks/subagent_start.py +71 -0
- package/dist/gaia-ops/hooks/subagent_stop.py +288 -0
- package/dist/gaia-ops/hooks/task_completed.py +70 -0
- package/dist/gaia-ops/hooks/user_prompt_submit.py +177 -0
- package/dist/gaia-ops/settings.json +72 -0
- package/dist/gaia-ops/skills/README.md +109 -0
- package/dist/gaia-ops/skills/agent-protocol/SKILL.md +105 -0
- package/dist/gaia-ops/skills/agent-protocol/examples.md +170 -0
- package/dist/gaia-ops/skills/agent-response/SKILL.md +53 -0
- package/dist/gaia-ops/skills/approval/SKILL.md +85 -0
- package/dist/gaia-ops/skills/approval/examples.md +140 -0
- package/dist/gaia-ops/skills/approval/reference.md +57 -0
- package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
- package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
- package/dist/gaia-ops/skills/context-updater/SKILL.md +76 -0
- package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
- package/dist/gaia-ops/skills/developer-patterns/SKILL.md +93 -0
- package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
- package/dist/gaia-ops/skills/execution/SKILL.md +66 -0
- package/dist/gaia-ops/skills/fast-queries/SKILL.md +47 -0
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +92 -0
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +22 -0
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +48 -0
- package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +73 -0
- package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
- package/dist/gaia-ops/skills/investigation/SKILL.md +77 -0
- package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +64 -0
- package/dist/gaia-ops/skills/reference.md +134 -0
- package/dist/gaia-ops/skills/security-tiers/SKILL.md +61 -0
- package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
- package/dist/gaia-ops/skills/skill-creation/SKILL.md +119 -0
- package/dist/gaia-ops/skills/specification/SKILL.md +186 -0
- package/dist/gaia-ops/skills/speckit-workflow/SKILL.md +165 -0
- package/dist/gaia-ops/skills/speckit-workflow/reference.md +117 -0
- package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +63 -0
- package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
- package/dist/gaia-ops/speckit/README.md +516 -0
- package/dist/gaia-ops/speckit/scripts/.gitkeep +0 -0
- package/dist/gaia-ops/speckit/templates/adr-template.md +118 -0
- package/dist/gaia-ops/speckit/templates/agent-file-template.md +23 -0
- package/dist/gaia-ops/speckit/templates/plan-template.md +227 -0
- package/dist/gaia-ops/speckit/templates/spec-template.md +140 -0
- package/dist/gaia-ops/speckit/templates/tasks-template.md +257 -0
- package/dist/gaia-ops/tools/context/README.md +132 -0
- package/dist/gaia-ops/tools/context/__init__.py +42 -0
- package/dist/gaia-ops/tools/context/_paths.py +20 -0
- package/dist/gaia-ops/tools/context/context_provider.py +476 -0
- package/dist/gaia-ops/tools/context/context_section_reader.py +330 -0
- package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
- package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
- package/dist/gaia-ops/tools/context/surface_router.py +278 -0
- package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
- package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
- package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
- package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
- package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
- package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
- package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
- package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
- package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
- package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +262 -0
- package/dist/gaia-ops/tools/memory/README.md +0 -0
- package/dist/gaia-ops/tools/memory/__init__.py +20 -0
- package/dist/gaia-ops/tools/memory/episodic.py +1196 -0
- package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
- package/dist/gaia-ops/tools/review/__init__.py +1 -0
- package/dist/gaia-ops/tools/review/review_engine.py +157 -0
- package/dist/gaia-ops/tools/scan/__init__.py +35 -0
- package/dist/gaia-ops/tools/scan/config.py +247 -0
- package/dist/gaia-ops/tools/scan/merge.py +212 -0
- package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
- package/dist/gaia-ops/tools/scan/registry.py +127 -0
- package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
- package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
- package/dist/gaia-ops/tools/scan/scanners/environment.py +324 -0
- package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
- package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
- package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
- package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
- package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
- package/dist/gaia-ops/tools/scan/setup.py +753 -0
- package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
- package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
- package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
- package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
- package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
- package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
- package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
- package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
- package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
- package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
- package/dist/gaia-ops/tools/scan/ui.py +624 -0
- package/dist/gaia-ops/tools/scan/verify.py +266 -0
- package/dist/gaia-ops/tools/scan/walk.py +118 -0
- package/dist/gaia-ops/tools/scan/workspace.py +85 -0
- package/dist/gaia-ops/tools/validation/README.md +244 -0
- package/dist/gaia-ops/tools/validation/__init__.py +17 -0
- package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
- package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
- package/dist/gaia-security/.claude-plugin/plugin.json +22 -0
- package/dist/gaia-security/config/universal-rules.json +10 -0
- package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-security/hooks/adapters/base.py +219 -0
- package/dist/gaia-security/hooks/adapters/channel.py +17 -0
- package/dist/gaia-security/hooks/adapters/claude_code.py +1477 -0
- package/dist/gaia-security/hooks/adapters/types.py +194 -0
- package/dist/gaia-security/hooks/adapters/utils.py +25 -0
- package/dist/gaia-security/hooks/hooks.json +57 -0
- package/dist/gaia-security/hooks/modules/__init__.py +15 -0
- package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +124 -0
- package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +576 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +215 -0
- package/dist/gaia-security/hooks/modules/context/context_cache.py +129 -0
- package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-security/hooks/modules/context/context_injector.py +427 -0
- package/dist/gaia-security/hooks/modules/context/context_writer.py +518 -0
- package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-security/hooks/modules/core/plugin_setup.py +558 -0
- package/dist/gaia-security/hooks/modules/core/state.py +179 -0
- package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-security/hooks/modules/identity/__init__.py +0 -0
- package/dist/gaia-security/hooks/modules/identity/identity_provider.py +21 -0
- package/dist/gaia-security/hooks/modules/identity/ops_identity.py +34 -0
- package/dist/gaia-security/hooks/modules/identity/security_identity.py +10 -0
- package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/memory/episode_writer.py +227 -0
- package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +128 -0
- package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-security/hooks/modules/security/__init__.py +89 -0
- package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-security/hooks/modules/security/approval_grants.py +912 -0
- package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-security/hooks/modules/security/approval_scopes.py +153 -0
- package/dist/gaia-security/hooks/modules/security/blocked_commands.py +584 -0
- package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +86 -0
- package/dist/gaia-security/hooks/modules/security/command_semantics.py +130 -0
- package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +850 -0
- package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-security/hooks/modules/session/session_event_injector.py +158 -0
- package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-security/hooks/modules/tools/__init__.py +25 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +708 -0
- package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +181 -0
- package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-security/hooks/modules/tools/task_validator.py +283 -0
- package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-security/hooks/post_tool_use.py +54 -0
- package/dist/gaia-security/hooks/pre_tool_use.py +383 -0
- package/dist/gaia-security/hooks/session_start.py +69 -0
- package/dist/gaia-security/hooks/stop_hook.py +69 -0
- package/dist/gaia-security/hooks/user_prompt_submit.py +177 -0
- package/dist/gaia-security/settings.json +58 -0
- package/git-hooks/commit-msg +41 -0
- package/hooks/README.md +8 -6
- package/hooks/adapters/channel.py +0 -25
- package/hooks/adapters/claude_code.py +364 -125
- package/hooks/elicitation_result.py +132 -0
- package/hooks/hooks.json +10 -1
- package/hooks/modules/README.md +3 -2
- package/hooks/modules/agents/contract_validator.py +3 -51
- package/hooks/modules/agents/response_contract.py +4 -8
- package/hooks/modules/agents/transcript_reader.py +4 -5
- package/hooks/modules/audit/__init__.py +4 -6
- package/hooks/modules/audit/event_detector.py +0 -2
- package/hooks/modules/audit/metrics.py +108 -187
- package/hooks/modules/audit/workflow_auditor.py +0 -4
- package/hooks/modules/audit/workflow_recorder.py +0 -5
- package/hooks/modules/context/compact_context_builder.py +1 -0
- package/hooks/modules/context/context_cache.py +129 -0
- package/hooks/modules/context/context_injector.py +18 -40
- package/hooks/modules/context/context_writer.py +1 -25
- package/hooks/modules/context/contracts_loader.py +7 -10
- package/hooks/modules/core/hook_entry.py +1 -0
- package/hooks/modules/core/paths.py +12 -13
- package/hooks/modules/core/plugin_mode.py +74 -4
- package/hooks/modules/core/plugin_setup.py +395 -23
- package/hooks/modules/events/__init__.py +1 -0
- package/hooks/modules/events/event_writer.py +210 -0
- package/hooks/modules/identity/ops_identity.py +18 -27
- package/hooks/modules/memory/episode_writer.py +1 -6
- package/hooks/modules/orchestrator/__init__.py +1 -0
- package/hooks/modules/orchestrator/delegate_mode.py +128 -0
- package/hooks/modules/security/__init__.py +2 -4
- package/hooks/modules/security/approval_constants.py +5 -1
- package/hooks/modules/security/approval_grants.py +189 -6
- package/hooks/modules/security/approval_messages.py +9 -21
- package/hooks/modules/security/blocked_commands.py +98 -34
- package/hooks/modules/security/command_semantics.py +0 -4
- package/hooks/modules/security/gitops_validator.py +1 -11
- package/hooks/modules/security/mutative_verbs.py +179 -38
- package/hooks/modules/security/tiers.py +1 -19
- package/hooks/modules/session/session_event_injector.py +1 -25
- package/hooks/modules/tools/bash_validator.py +310 -94
- package/hooks/modules/tools/shell_parser.py +0 -1
- package/hooks/modules/tools/task_validator.py +9 -29
- package/hooks/post_tool_use.py +0 -72
- package/hooks/pre_tool_use.py +42 -102
- package/hooks/session_start.py +4 -2
- package/hooks/subagent_start.py +6 -2
- package/hooks/subagent_stop.py +1 -13
- package/hooks/user_prompt_submit.py +119 -37
- package/index.js +1 -1
- package/package.json +5 -3
- package/skills/README.md +3 -5
- package/skills/agent-protocol/SKILL.md +17 -16
- package/skills/agent-protocol/examples.md +6 -6
- package/skills/agent-response/SKILL.md +11 -14
- package/skills/approval/SKILL.md +28 -13
- package/skills/approval/reference.md +2 -2
- package/skills/execution/SKILL.md +1 -1
- package/skills/gaia-patterns/SKILL.md +2 -3
- package/skills/orchestrator-approval/SKILL.md +22 -50
- package/skills/security-tiers/SKILL.md +1 -1
- package/templates/README.md +9 -9
- package/templates/managed-settings.template.json +43 -0
- package/tools/gaia_simulator/runner.py +34 -1
- package/tools/scan/orchestrator.py +13 -0
- package/tools/scan/scanners/base.py +8 -0
- package/tools/scan/scanners/git.py +78 -0
- package/tools/scan/scanners/infrastructure.py +65 -0
- package/tools/scan/scanners/stack.py +110 -0
- package/tools/scan/setup.py +120 -13
- package/tools/scan/workspace.py +85 -0
- package/config/context-contracts.aws.json +0 -42
- package/config/context-contracts.gcp.json +0 -39
- package/skills/project-dispatch/SKILL.md +0 -34
- package/templates/settings.template.json +0 -226
|
@@ -36,20 +36,20 @@ Every response MUST end with a single fenced `json:contract` block.
|
|
|
36
36
|
|
|
37
37
|
### agent_status (always required)
|
|
38
38
|
|
|
39
|
-
- `plan_status`
|
|
40
|
-
- `agent_id`
|
|
41
|
-
- `pending_steps`
|
|
42
|
-
- `next_action`
|
|
39
|
+
- `plan_status` -- one of the 5 valid states below
|
|
40
|
+
- `agent_id` -- generate once, reuse across responses
|
|
41
|
+
- `pending_steps` -- remaining work (`[]` when done)
|
|
42
|
+
- `next_action` -- `"done"` or what happens next
|
|
43
43
|
|
|
44
44
|
### evidence_report (always required)
|
|
45
45
|
|
|
46
46
|
All 7 fields validated by runtime. Use `[]` when not applicable.
|
|
47
47
|
Keep each to 1-3 items unless the task genuinely needs more.
|
|
48
48
|
|
|
49
|
-
- `key_outputs`
|
|
50
|
-
- `verbatim_outputs`
|
|
51
|
-
- `cross_layer_impacts`
|
|
52
|
-
- `open_gaps`
|
|
49
|
+
- `key_outputs` -- actionable findings, not descriptions of what you ran. Highlight what matters: what is wrong, what changed, what needs attention.
|
|
50
|
+
- `verbatim_outputs` -- literal command output; truncate at ~100 lines
|
|
51
|
+
- `cross_layer_impacts` -- adjacent surfaces affected
|
|
52
|
+
- `open_gaps` -- what remains unverified; never imply certainty
|
|
53
53
|
|
|
54
54
|
### consolidation_report (when multi-surface)
|
|
55
55
|
|
|
@@ -61,30 +61,31 @@ Fields: `ownership_assessment`, `confirmed_findings`,
|
|
|
61
61
|
|
|
62
62
|
For examples, read `examples.md` in this skill directory.
|
|
63
63
|
|
|
64
|
-
### approval_request (when REVIEW
|
|
64
|
+
### approval_request (when REVIEW)
|
|
65
65
|
|
|
66
|
-
Required when `plan_status` is `REVIEW
|
|
66
|
+
Required when `plan_status` is `REVIEW`. Otherwise `null`.
|
|
67
67
|
|
|
68
68
|
Fields: `operation`, `exact_content`, `scope`, `risk_level`, `rollback`, `verification`.
|
|
69
|
-
|
|
69
|
+
When a hook blocked a T3 command with `[T3_BLOCKED]` and an `approval_id`:
|
|
70
|
+
- Do NOT retry the command -- retrying generates new nonces in a loop
|
|
71
|
+
- Set `plan_status` to `REVIEW` and include `approval_id` in `approval_request`
|
|
72
|
+
- The orchestrator will resume you after user approval; only then retry
|
|
70
73
|
|
|
71
74
|
## State Machine
|
|
72
75
|
|
|
73
76
|
| Status | Meaning |
|
|
74
77
|
|--------|---------|
|
|
75
78
|
| `IN_PROGRESS` | Active work: investigating, planning, executing, retrying (max 2 cycles) |
|
|
76
|
-
| `REVIEW` | Presenting plan or analysis for user feedback.
|
|
77
|
-
| `AWAITING_APPROVAL` | Hook blocked a T3 command. Nonce present. |
|
|
79
|
+
| `REVIEW` | Presenting plan or analysis for user feedback. May include `approval_id` when hook-blocked. |
|
|
78
80
|
| `COMPLETE` | Task finished |
|
|
79
|
-
| `BLOCKED` | Cannot proceed
|
|
81
|
+
| `BLOCKED` | Cannot proceed -- escalated |
|
|
80
82
|
| `NEEDS_INPUT` | Missing information from user |
|
|
81
83
|
|
|
82
84
|
### Transitions
|
|
83
85
|
|
|
84
86
|
```
|
|
85
87
|
IN_PROGRESS -> COMPLETE (T0/T1/T2)
|
|
86
|
-
IN_PROGRESS -> REVIEW -> IN_PROGRESS -> COMPLETE (plan-first)
|
|
87
|
-
IN_PROGRESS -> AWAITING_APPROVAL -> IN_PROGRESS -> COMPLETE (hook-blocked T3)
|
|
88
|
+
IN_PROGRESS -> REVIEW -> IN_PROGRESS -> COMPLETE (plan-first or hook-blocked T3)
|
|
88
89
|
IN_PROGRESS -> BLOCKED | NEEDS_INPUT (any point)
|
|
89
90
|
IN_PROGRESS -> IN_PROGRESS (retry, max 2)
|
|
90
91
|
```
|
|
@@ -106,22 +106,22 @@ See `SKILL.md` for the schema definition and field rules.
|
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
##
|
|
109
|
+
## REVIEW with approval_id (hook blocked T3 command)
|
|
110
110
|
|
|
111
111
|
```json:contract
|
|
112
112
|
{
|
|
113
113
|
"agent_status": {
|
|
114
|
-
"plan_status": "
|
|
114
|
+
"plan_status": "REVIEW",
|
|
115
115
|
"agent_id": "af1d9b7",
|
|
116
116
|
"pending_steps": ["execute git push", "verify Flux reconciliation"],
|
|
117
|
-
"next_action": "Hook blocked git push -- awaiting
|
|
117
|
+
"next_action": "Hook blocked git push -- awaiting user approval"
|
|
118
118
|
},
|
|
119
119
|
"evidence_report": {
|
|
120
120
|
"patterns_checked": ["git branch naming in flux/clusters/"],
|
|
121
121
|
"files_checked": ["flux/apps/qxo-api/helmrelease.yaml"],
|
|
122
122
|
"commands_run": ["git diff HEAD -> 1 file changed", "git push origin main -> BLOCKED by hook"],
|
|
123
|
-
"key_outputs": ["Push blocked by
|
|
124
|
-
"verbatim_outputs": ["
|
|
123
|
+
"key_outputs": ["Push blocked by security hook, approval_id issued"],
|
|
124
|
+
"verbatim_outputs": ["[T3_BLOCKED] MUTATIVE operation requires user approval. approval_id: a1b2c3..."],
|
|
125
125
|
"cross_layer_impacts": ["Flux will reconcile HelmRelease on push"],
|
|
126
126
|
"open_gaps": []
|
|
127
127
|
},
|
|
@@ -133,7 +133,7 @@ See `SKILL.md` for the schema definition and field rules.
|
|
|
133
133
|
"risk_level": "MEDIUM",
|
|
134
134
|
"rollback": "git revert HEAD && git push",
|
|
135
135
|
"verification": "flux get hr -n qxo -> reconciled",
|
|
136
|
-
"
|
|
136
|
+
"approval_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
```
|
|
@@ -12,12 +12,12 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
Agent returns json:contract
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
|- COMPLETE -> Summarize key_outputs (3-5 bullets)
|
|
16
|
+
|- NEEDS_INPUT -> AskUserQuestion, then SendMessage answer back
|
|
17
|
+
|- REVIEW -> Load Skill("orchestrator-approval") if approval_id present,
|
|
18
|
+
| otherwise AskUserQuestion (execute/modify/cancel)
|
|
19
|
+
|- BLOCKED -> Present open_gaps via AskUserQuestion
|
|
20
|
+
+- IN_PROGRESS -> SendMessage to resume agent
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Mandatory Actions per Status
|
|
@@ -25,9 +25,8 @@ Agent returns json:contract
|
|
|
25
25
|
| Status | Action | Tool |
|
|
26
26
|
|---|---|---|
|
|
27
27
|
| `COMPLETE` | Summarize `key_outputs` in 3-5 bullets. Mention `cross_layer_impacts` and `open_gaps` if non-empty. Say "ask for details" if `verbatim_outputs` exists. | Direct response |
|
|
28
|
-
| `NEEDS_INPUT` | Present the agent's question with options | `AskUserQuestion`
|
|
29
|
-
| `REVIEW` |
|
|
30
|
-
| `AWAITING_APPROVAL` | Do not handle directly | `Skill("orchestrator-approval")` |
|
|
28
|
+
| `NEEDS_INPUT` | Present the agent's question with options | `AskUserQuestion` -> `SendMessage` |
|
|
29
|
+
| `REVIEW` | If `approval_request.approval_id` is present: load `Skill("orchestrator-approval")`. Otherwise: present plan with options execute / modify / cancel. | `AskUserQuestion` -> `SendMessage` |
|
|
31
30
|
| `BLOCKED` | Present alternatives from `open_gaps` | `AskUserQuestion` |
|
|
32
31
|
| `IN_PROGRESS` | Agent was interrupted, let it continue | `SendMessage` |
|
|
33
32
|
|
|
@@ -35,10 +34,10 @@ Agent returns json:contract
|
|
|
35
34
|
|
|
36
35
|
| Field | When to surface |
|
|
37
36
|
|---|---|
|
|
38
|
-
| `key_outputs` | Always
|
|
39
|
-
| `verbatim_outputs` | Only when user asks for details
|
|
37
|
+
| `key_outputs` | Always -- base your summary on these |
|
|
38
|
+
| `verbatim_outputs` | Only when user asks for details -- relay in code blocks |
|
|
40
39
|
| `cross_layer_impacts` | Always mention if non-empty |
|
|
41
|
-
| `open_gaps` | Always mention
|
|
40
|
+
| `open_gaps` | Always mention -- never imply certainty |
|
|
42
41
|
| `consolidation_report` | Check for `conflicts` and `next_best_agent` |
|
|
43
42
|
| `next_best_agent` | Ask user if they want to dispatch |
|
|
44
43
|
|
|
@@ -51,6 +50,4 @@ If agents conflict, present both sides and ask user to decide.
|
|
|
51
50
|
|
|
52
51
|
| Situation | Action |
|
|
53
52
|
|---|---|
|
|
54
|
-
| Hook blocks a command | Relay message verbatim. Do not try alternatives. |
|
|
55
|
-
| Agent contradicts another | Show both findings, flag conflict, ask user. |
|
|
56
53
|
| Malformed contract | Resume agent with repair instructions (max 2 retries). |
|
package/skills/approval/SKILL.md
CHANGED
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
The plan is a contract. The user approves the exact contract
|
|
13
|
+
The plan is a contract. The user approves the exact contract --
|
|
14
14
|
not a vague intent. Structure your plan in the `approval_request`
|
|
15
15
|
field of your `json:contract` so the orchestrator can present it
|
|
16
16
|
directly to the user.
|
|
@@ -31,9 +31,9 @@ with these 6 fields:
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
When a hook blocked your command with an `approval_id`, also include:
|
|
35
35
|
```json
|
|
36
|
-
"
|
|
36
|
+
"approval_id": "hex from hook deny response"
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
### Risk Levels
|
|
@@ -47,24 +47,39 @@ For `AWAITING_APPROVAL` (hook-blocked), also include:
|
|
|
47
47
|
|
|
48
48
|
## Which Status to Emit
|
|
49
49
|
|
|
50
|
-
- `REVIEW`
|
|
51
|
-
- `
|
|
50
|
+
- `REVIEW` -- presenting a plan before executing (no hook block)
|
|
51
|
+
- `REVIEW` with `approval_id` -- hook blocked your command with an approval_id
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Both use `REVIEW` as the plan_status. The presence or absence of
|
|
54
|
+
`approval_id` in `approval_request` tells the orchestrator which
|
|
55
|
+
handling path to take.
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
## Hook Block Flow
|
|
58
|
+
|
|
59
|
+
When a hook blocks your command with `[T3_BLOCKED]` and an `approval_id`:
|
|
60
|
+
|
|
61
|
+
1. **STOP** -- do NOT retry the command. Retrying generates a new nonce
|
|
62
|
+
each time, creating an infinite loop.
|
|
63
|
+
2. **Report REVIEW** -- set `plan_status` to `REVIEW` in your `json:contract`.
|
|
64
|
+
3. **Include the approval_id** -- copy the hex identifier from the hook deny
|
|
65
|
+
response into `approval_request.approval_id`.
|
|
66
|
+
4. **Wait** -- the orchestrator presents your plan to the user. When the user
|
|
67
|
+
approves, the orchestrator resumes you with the grant activated.
|
|
68
|
+
5. **Then retry** -- only after the orchestrator resumes you, retry the command.
|
|
69
|
+
|
|
70
|
+
The hook deny message looks like:
|
|
56
71
|
```
|
|
57
|
-
|
|
72
|
+
[T3_BLOCKED] This command requires user approval.
|
|
73
|
+
Do NOT retry this command. Report REVIEW with this approval_id in your json:contract.
|
|
74
|
+
approval_id: <hex>
|
|
58
75
|
```
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
the orchestrator extracts it silently.
|
|
62
|
-
|
|
63
|
-
If you lose the nonce, re-attempt the command for a fresh one.
|
|
77
|
+
If you lose the approval_id, re-attempt the command once for a fresh one.
|
|
64
78
|
|
|
65
79
|
## Anti-Patterns
|
|
66
80
|
|
|
81
|
+
- **Retrying after T3_BLOCKED** -- generates a new nonce, causes infinite loop
|
|
67
82
|
- Presenting approval without all 6 fields in `approval_request`
|
|
68
83
|
- Putting approval fields in text only without the JSON object
|
|
69
84
|
- Treating prior approvals as valid for new operations
|
|
70
|
-
- Fabricating or paraphrasing the
|
|
85
|
+
- Fabricating or paraphrasing the approval_id token
|
|
@@ -43,10 +43,10 @@ These 6 fields MUST appear in the `approval_request` object of your `json:contra
|
|
|
43
43
|
| `rollback` | `"terraform -chdir=/infra/dev apply -target=module.vpc -var='cidr=10.0.0.0/16'"` |
|
|
44
44
|
| `verification` | `"terraform -chdir=/infra/dev output vpc_id -- expect vpc-xxx"` |
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
When a hook blocked the command, also include:
|
|
47
47
|
| Field | Example value |
|
|
48
48
|
|-------|---------------|
|
|
49
|
-
| `
|
|
49
|
+
| `approval_id` | `"a1b2c3d4e5f6..."` (hex from hook deny response) |
|
|
50
50
|
|
|
51
51
|
### Files Affected
|
|
52
52
|
|
|
@@ -24,7 +24,7 @@ system in a broken state.
|
|
|
24
24
|
|
|
25
25
|
Before executing ANY approved operation:
|
|
26
26
|
|
|
27
|
-
- [ ]
|
|
27
|
+
- [ ] User approved via AskUserQuestion and ElicitationResult hook activated the grant
|
|
28
28
|
- [ ] Capture current state — know what you can roll back to
|
|
29
29
|
- [ ] Plan still valid — re-run dry-run if time has passed
|
|
30
30
|
- [ ] Commands will not prompt for interactive input
|
|
@@ -27,8 +27,7 @@ Domain knowledge for the gaia-ops meta-system. For the Component Map details, se
|
|
|
27
27
|
5. Post-Tool Hook — audit + metrics
|
|
28
28
|
↓
|
|
29
29
|
6. Orchestrator processes `json:contract` block (plan_status)
|
|
30
|
-
├─ REVIEW → present plan, get feedback → resume
|
|
31
|
-
├─ AWAITING_APPROVAL → present plan + nonce relay → resume
|
|
30
|
+
├─ REVIEW → present plan, get feedback → resume (with approval_id if hook-blocked)
|
|
32
31
|
├─ NEEDS_INPUT → ask user → resume
|
|
33
32
|
└─ COMPLETE → respond to user
|
|
34
33
|
```
|
|
@@ -38,7 +37,7 @@ Domain knowledge for the gaia-ops meta-system. For the Component Map details, se
|
|
|
38
37
|
- **Binary Delegation:** The orchestrator always delegates. Its only tools are Agent and AskUserQuestion.
|
|
39
38
|
- **Agent Instantiation:** identity (.md) + skills (injected) + project-context (contracts) + orchestrator request.
|
|
40
39
|
- **Security Tiers:** T0 (read) → T1 (validate) → T2 (simulate) → T3 (realize, requires approval).
|
|
41
|
-
- **T3 Flow:** IN_PROGRESS → REVIEW → IN_PROGRESS → COMPLETE (plan-first
|
|
40
|
+
- **T3 Flow:** IN_PROGRESS → REVIEW → IN_PROGRESS → COMPLETE (plan-first or hook-blocked with approval_id).
|
|
42
41
|
- **Consolidation Loop:** for multi-surface work, Gaia may dispatch more than one round of agents, but only while gaps are actionable and evidence is still improving.
|
|
43
42
|
- **Principle:** Skills teach process. Agents teach identity and domain knowledge. Runtime enforces deterministic contracts. Never duplicate.
|
|
44
43
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestrator-approval
|
|
3
|
-
description: Use when processing
|
|
3
|
+
description: Use when processing REVIEW with approval_id from a subagent -- enforces showing values before asking for user consent
|
|
4
4
|
metadata:
|
|
5
5
|
user-invocable: false
|
|
6
6
|
type: discipline
|
|
@@ -9,9 +9,9 @@ metadata:
|
|
|
9
9
|
# Orchestrator Approval
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
THIS SKILL HANDLES
|
|
13
|
-
REVIEW
|
|
14
|
-
NEVER
|
|
12
|
+
THIS SKILL HANDLES REVIEW WITH approval_id (hook-blocked T3).
|
|
13
|
+
Plain REVIEW (plan-first, no approval_id) is handled directly by the orchestrator.
|
|
14
|
+
NEVER PRESENT AN APPROVAL WITHOUT SHOWING THE USER
|
|
15
15
|
(1) WHAT WILL HAPPEN, (2) EXACT CONTENT/COMMAND, (3) WHAT IT MODIFIES.
|
|
16
16
|
```
|
|
17
17
|
|
|
@@ -19,13 +19,13 @@ NEVER RELAY APPROVE:<nonce> WITHOUT SHOWING THE USER
|
|
|
19
19
|
|
|
20
20
|
The orchestrator sits between the subagent and the user. The subagent presents a plan; the user decides. But the user cannot decide on information they have not seen. Every approval prompt must contain enough detail for informed consent -- not a summary, not a reference to "the plan above", not an offer to show details on request. The values go in the prompt, every time, before the question is asked.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
When a hook blocks a T3 command, it writes a pending approval and returns an `approval_id` in the deny response. The subagent includes this `approval_id` in its `approval_request`. The orchestrator presents the plan via AskUserQuestion with structured options (Approve / Modify / Reject). When the user selects "Approve", the PostToolUse hook for AskUserQuestion fires and activates the pending grant. No nonce or approval_id is relayed through SendMessage -- grant activation is handled entirely by the hook.
|
|
23
23
|
|
|
24
|
-
**Scope:** This skill applies ONLY when a subagent emits `
|
|
24
|
+
**Scope:** This skill applies ONLY when a subagent emits `REVIEW` with an `approval_id` in its `approval_request`. Without `approval_id`, the orchestrator handles REVIEW directly.
|
|
25
25
|
|
|
26
26
|
## Mandatory Presentation Block
|
|
27
27
|
|
|
28
|
-
Every `
|
|
28
|
+
Every hook-blocked `REVIEW` presented to the user MUST include these 5 fields.
|
|
29
29
|
Read them from the `approval_request` object in the agent's `json:contract` block:
|
|
30
30
|
|
|
31
31
|
| Field | Source in `approval_request` | Content |
|
|
@@ -36,57 +36,29 @@ Read them from the `approval_request` object in the agent's `json:contract` bloc
|
|
|
36
36
|
| **RISK_LEVEL** | `approval_request.risk_level` | LOW / MEDIUM / HIGH / CRITICAL |
|
|
37
37
|
| **ROLLBACK** | `approval_request.rollback` | How to undo if wrong |
|
|
38
38
|
|
|
39
|
-
The nonce comes from `approval_request.nonce` (present only for `AWAITING_APPROVAL`).
|
|
40
|
-
|
|
41
|
-
Present these fields, then use AskUserQuestion with labeled options: **Approve / Modify / Reject**.
|
|
42
|
-
|
|
43
39
|
## Rules
|
|
44
40
|
|
|
45
|
-
**1.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
**2. Never synthesize a nonce.**
|
|
49
|
-
Only use `APPROVE:<nonce>` with a real hex nonce from the subagent's latest blocked command output. Never construct tokens like `APPROVE:commit`, `APPROVE:git push`, or `APPROVE:terraform apply prod`.
|
|
50
|
-
|
|
51
|
-
**3. Approval intent vs nonce relay.**
|
|
52
|
-
If the user approves but no nonce exists yet, store that as intent only. Resume the subagent with natural language and let it continue until the hook generates a real nonce.
|
|
53
|
-
|
|
54
|
-
**4. Scope guard.**
|
|
55
|
-
When a nonce arrives, compare the blocked command's scope to what the user originally approved. If the command expands scope, changes operation, or targets something materially different -- present the new scope and ask again.
|
|
56
|
-
|
|
57
|
-
**5. Fresh presentation every time.**
|
|
58
|
-
Each `AWAITING_APPROVAL` requires its own presentation with all mandatory fields. Prior approvals do not carry forward.
|
|
59
|
-
|
|
60
|
-
## Nonce Relay Procedure
|
|
61
|
-
|
|
62
|
-
1. Extract the 5 mandatory fields from `approval_request` in the subagent's `json:contract` block. Extract the nonce from `approval_request.nonce` (present only for `AWAITING_APPROVAL`).
|
|
63
|
-
2. Present to the user via AskUserQuestion with all mandatory fields populated. Options: **Approve / Modify / Reject**. Never include the nonce in user-facing text.
|
|
64
|
-
3. On user approval:
|
|
65
|
-
- If nonce exists: resume the subagent via SendMessage(to: agentId) with `APPROVE:<nonce>` as the message.
|
|
66
|
-
- If no nonce yet: store approval intent. Resume subagent via SendMessage with natural language describing the approved direction.
|
|
67
|
-
4. On scope change: if the eventual blocked command differs materially from what the user approved, present the new scope with all mandatory fields and ask again.
|
|
41
|
+
**1. Grant activates through the PostToolUse hook for AskUserQuestion -- not SendMessage.**
|
|
42
|
+
Resume the subagent via SendMessage with natural language only (e.g., "Proceed with the approved operation"). Never include any nonce, approval_id, or APPROVE: token.
|
|
68
43
|
|
|
69
|
-
**
|
|
70
|
-
|
|
71
|
-
gate -- the user approved the plan through the orchestrator, and now confirms the
|
|
72
|
-
actual command execution through the native dialog. Subsequent commands within the
|
|
73
|
-
approval TTL window proceed without the native dialog.
|
|
44
|
+
**2. Scope guard.**
|
|
45
|
+
Compare the blocked command's scope to what the user originally approved. If the command expands scope, changes operation, or targets something materially different -- present the new scope and ask again.
|
|
74
46
|
|
|
75
|
-
|
|
47
|
+
**3. Fresh presentation every time.**
|
|
48
|
+
Each hook-blocked REVIEW requires its own presentation with all mandatory fields. Prior approvals do not carry forward.
|
|
76
49
|
|
|
77
|
-
|
|
50
|
+
## Approval Procedure
|
|
78
51
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- *"The user already approved this type of operation"* -- Each AWAITING_APPROVAL requires fresh presentation.
|
|
84
|
-
- *"I can construct the nonce from the operation description"* -- Nonces are hex tokens from the hook, never synthesized.
|
|
52
|
+
1. Extract the 5 mandatory fields from `approval_request` in the subagent's `json:contract` block.
|
|
53
|
+
2. Present to the user via AskUserQuestion with all mandatory fields populated. Use exactly these options: **Approve / Modify / Reject**. Never include the approval_id in user-facing text.
|
|
54
|
+
3. On "Approve": resume the subagent via SendMessage with natural language describing the approved direction.
|
|
55
|
+
4. On scope change: present the new scope with all mandatory fields and ask again.
|
|
85
56
|
|
|
86
57
|
## Anti-Patterns
|
|
87
58
|
|
|
88
59
|
- **Summary-only approval** -- presenting "Deploy to dev?" without the exact command, files, or rollback.
|
|
89
|
-
- **
|
|
90
|
-
- **
|
|
91
|
-
- **Implicit carry-forward** -- treating a prior approval as valid for a new AWAITING_APPROVAL.
|
|
60
|
+
- **Token relay in SendMessage** -- including approval_id or nonce in the resume message.
|
|
61
|
+
- **Implicit carry-forward** -- treating a prior approval as valid for a new hook-blocked REVIEW.
|
|
92
62
|
- **Details on demand** -- offering to show the plan instead of showing it upfront.
|
|
63
|
+
- **"It's just a small change"** -- size does not change the contract. Show exact content regardless.
|
|
64
|
+
- **"The subagent already showed it"** -- show it again in the approval prompt.
|
|
@@ -54,7 +54,7 @@ Conditional commands like `git branch` are safe for listing but T3 with mutative
|
|
|
54
54
|
|
|
55
55
|
## T3 Workflow
|
|
56
56
|
|
|
57
|
-
For T3 operations, follow the state flow in `agent-protocol`: IN_PROGRESS -- REVIEW -- IN_PROGRESS -- COMPLETE (plan-first
|
|
57
|
+
For T3 operations, follow the state flow in `agent-protocol`: IN_PROGRESS -- REVIEW -- IN_PROGRESS -- COMPLETE (plan-first or hook-blocked with approval_id).
|
|
58
58
|
|
|
59
59
|
On-demand workflow skills (read from disk when needed):
|
|
60
60
|
- `.claude/skills/approval/SKILL.md` -- informed-consent plan quality and approval presentation
|
package/templates/README.md
CHANGED
|
@@ -16,12 +16,12 @@ Generates final file in project
|
|
|
16
16
|
|
|
17
17
|
## Available Templates
|
|
18
18
|
|
|
19
|
-
### `settings.template.json`
|
|
19
|
+
### `managed-settings.template.json`
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Reference template for enterprise deployment via Claude.ai Admin Console or `/etc/claude-code/managed-settings.json`. Contains wildcard deny rules with highest precedence (cannot be overridden by user/project settings). Includes `disableBypassPermissionsMode` to prevent `--dangerously-skip-permissions`.
|
|
22
22
|
|
|
23
|
-
**
|
|
24
|
-
**Output
|
|
23
|
+
**Deployed by:** Organization admin (not automated)
|
|
24
|
+
**Output:** `/etc/claude-code/managed-settings.json` (Linux) or Admin Console
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -40,7 +40,7 @@ Template for the project governance document. Placeholders are filled with value
|
|
|
40
40
|
|
|
41
41
|
## Note on CLAUDE.md
|
|
42
42
|
|
|
43
|
-
Orchestrator identity is no longer generated from a template. It is injected dynamically by the UserPromptSubmit hook via `ops_identity.py` and on-demand skills (`
|
|
43
|
+
Orchestrator identity is no longer generated from a template. It is injected dynamically by the UserPromptSubmit hook via `ops_identity.py` with deterministic surface routing and on-demand skills (`agent-response`).
|
|
44
44
|
|
|
45
45
|
## Usage
|
|
46
46
|
|
|
@@ -56,15 +56,15 @@ node node_modules/@jaguilar87/gaia-ops/bin/gaia-update.js
|
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
templates/
|
|
59
|
-
├── settings.template.json
|
|
60
|
-
├── governance.template.md
|
|
59
|
+
├── managed-settings.template.json # Enterprise deny rules (manual deploy)
|
|
60
|
+
├── governance.template.md # Project governance (interpolated)
|
|
61
61
|
└── README.md
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
**Scripts using templates:**
|
|
65
65
|
- `bin/gaia-scan.py` - Installer
|
|
66
|
-
- `bin/gaia-update.js` - Updater
|
|
66
|
+
- `bin/gaia-update.js` - Updater (permissions merge into settings.local.json)
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
|
-
**Updated:** 2026-03-
|
|
70
|
+
**Updated:** 2026-03-26 | **Templates:** 2
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": [
|
|
3
|
+
"Managed settings template for enterprise/organization deployment.",
|
|
4
|
+
"Deploy to: /etc/claude-code/managed-settings.json (Linux/WSL)",
|
|
5
|
+
" /Library/Application Support/ClaudeCode/managed-settings.json (macOS)",
|
|
6
|
+
" Or via Claude.ai Admin > Claude Code > Managed Settings",
|
|
7
|
+
"",
|
|
8
|
+
"These rules have the HIGHEST precedence and CANNOT be overridden by",
|
|
9
|
+
"user, project, or local settings. They are the ultimate security gate."
|
|
10
|
+
],
|
|
11
|
+
"permissions": {
|
|
12
|
+
"deny": [
|
|
13
|
+
"Bash(aws * delete-*:*)",
|
|
14
|
+
"Bash(aws * terminate-*:*)",
|
|
15
|
+
"Bash(az * delete:*)",
|
|
16
|
+
"Bash(gcloud * delete:*)",
|
|
17
|
+
"Bash(gsutil rb:*)",
|
|
18
|
+
"Bash(gsutil rm:*)",
|
|
19
|
+
"Bash(gcloud storage rm:*)",
|
|
20
|
+
"Bash(kubectl delete:*)",
|
|
21
|
+
"Bash(kubectl drain:*)",
|
|
22
|
+
"Bash(terraform destroy:*)",
|
|
23
|
+
"Bash(terragrunt destroy:*)",
|
|
24
|
+
"Bash(terragrunt run-all destroy:*)",
|
|
25
|
+
"Bash(helm uninstall:*)",
|
|
26
|
+
"Bash(helm delete:*)",
|
|
27
|
+
"Bash(flux uninstall:*)",
|
|
28
|
+
"Bash(docker system prune:*)",
|
|
29
|
+
"Bash(docker volume prune:*)",
|
|
30
|
+
"Bash(git push --force:*)",
|
|
31
|
+
"Bash(git push -f:*)",
|
|
32
|
+
"Bash(git reset --hard:*)",
|
|
33
|
+
"Bash(gh repo delete:*)",
|
|
34
|
+
"Bash(glab project delete:*)",
|
|
35
|
+
"Bash(dd:*)",
|
|
36
|
+
"Bash(fdisk:*)",
|
|
37
|
+
"Bash(mkfs:*)",
|
|
38
|
+
"Bash(mkfs.*:*)"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"disableBypassPermissionsMode": "disable",
|
|
42
|
+
"allowManagedHooksOnly": false
|
|
43
|
+
}
|
|
@@ -352,6 +352,39 @@ class HookRunner:
|
|
|
352
352
|
|
|
353
353
|
return base_dir
|
|
354
354
|
|
|
355
|
+
# Tools that the orchestrator is allowed to use directly.
|
|
356
|
+
# Payloads for these tools should NOT get agent_id injected, because
|
|
357
|
+
# they are orchestrator-level operations (dispatch, communication).
|
|
358
|
+
_ORCHESTRATOR_TOOLS = frozenset({
|
|
359
|
+
"agent", "task", "sendmessage", "skill",
|
|
360
|
+
"taskcreate", "taskupdate", "tasklist", "taskget",
|
|
361
|
+
"toolsearch", "websearch", "webfetch", "askuserquestion",
|
|
362
|
+
"stop", # stop_hook payloads are not subject to delegate mode
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
def _prepare_payload(self, event: ReplayEvent) -> str:
|
|
366
|
+
"""Serialize the event payload for the hook subprocess.
|
|
367
|
+
|
|
368
|
+
Injects ``agent_id`` into tool-call payloads that lack one, so
|
|
369
|
+
delegate mode recognises them as subagent context instead of
|
|
370
|
+
blocking them as orchestrator calls. Agent/SendMessage/Task
|
|
371
|
+
payloads are left untouched since the orchestrator context is
|
|
372
|
+
correct for those.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
event: The ReplayEvent being replayed.
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
JSON string to feed to the hook subprocess via stdin.
|
|
379
|
+
"""
|
|
380
|
+
payload = event.stdin_payload
|
|
381
|
+
tool_name = (payload.get("tool_name") or event.tool_name or "").lower()
|
|
382
|
+
|
|
383
|
+
if not payload.get("agent_id") and tool_name not in self._ORCHESTRATOR_TOOLS:
|
|
384
|
+
payload = {**payload, "agent_id": "replay-simulator"}
|
|
385
|
+
|
|
386
|
+
return json.dumps(payload)
|
|
387
|
+
|
|
355
388
|
def _resolve_hook_script(self, hook_name: str) -> Path:
|
|
356
389
|
"""Resolve hook name to script path.
|
|
357
390
|
|
|
@@ -403,7 +436,7 @@ class HookRunner:
|
|
|
403
436
|
try:
|
|
404
437
|
result = subprocess.run(
|
|
405
438
|
[sys.executable, str(script_path)],
|
|
406
|
-
input=
|
|
439
|
+
input=self._prepare_payload(event),
|
|
407
440
|
capture_output=True,
|
|
408
441
|
text=True,
|
|
409
442
|
env=env,
|
|
@@ -37,6 +37,7 @@ from tools.scan.merge import (
|
|
|
37
37
|
)
|
|
38
38
|
from tools.scan.registry import ScannerRegistry
|
|
39
39
|
from tools.scan.scanners.base import BaseScanner, ScanResult
|
|
40
|
+
from tools.scan.workspace import WorkspaceInfo, detect_workspace_type
|
|
40
41
|
|
|
41
42
|
logger = logging.getLogger(__name__)
|
|
42
43
|
|
|
@@ -267,12 +268,24 @@ class ScanOrchestrator:
|
|
|
267
268
|
existing_sections = existing_full.get("sections", {})
|
|
268
269
|
existing_metadata = existing_full.get("metadata", {})
|
|
269
270
|
|
|
271
|
+
# Step 1.5: Detect workspace type BEFORE running scanners
|
|
272
|
+
workspace_info = detect_workspace_type(root)
|
|
273
|
+
if workspace_info.is_multi_repo:
|
|
274
|
+
logger.info(
|
|
275
|
+
"Multi-repo workspace: %d repos detected",
|
|
276
|
+
len(workspace_info.repo_dirs),
|
|
277
|
+
)
|
|
278
|
+
|
|
270
279
|
# Step 2: Run all scanners
|
|
271
280
|
scanners = self.registry.get_all()
|
|
272
281
|
if self.config.scanners:
|
|
273
282
|
requested = set(self.config.scanners)
|
|
274
283
|
scanners = [s for s in scanners if s.SCANNER_NAME in requested]
|
|
275
284
|
|
|
285
|
+
# Pass workspace info to each scanner instance
|
|
286
|
+
for scanner in scanners:
|
|
287
|
+
scanner.workspace_info = workspace_info
|
|
288
|
+
|
|
276
289
|
scanner_results: Dict[str, ScanResult] = {}
|
|
277
290
|
all_warnings: List[str] = []
|
|
278
291
|
all_errors: List[str] = []
|
|
@@ -53,8 +53,16 @@ class BaseScanner(ABC):
|
|
|
53
53
|
Performance:
|
|
54
54
|
- SHOULD complete in under 3 seconds for typical projects
|
|
55
55
|
- MUST respect 2-second timeout for --version calls
|
|
56
|
+
|
|
57
|
+
Optional workspace_info attribute:
|
|
58
|
+
- Set by the orchestrator before scan() when workspace type has been
|
|
59
|
+
pre-detected. Scanners can check self.workspace_info for multi-repo
|
|
60
|
+
awareness. Defaults to None (single-repo assumed).
|
|
56
61
|
"""
|
|
57
62
|
|
|
63
|
+
def __init__(self) -> None:
|
|
64
|
+
self.workspace_info = None # Set by orchestrator if available
|
|
65
|
+
|
|
58
66
|
@property
|
|
59
67
|
@abstractmethod
|
|
60
68
|
def SCANNER_NAME(self) -> str:
|