@jaguilar87/gaia 5.0.2 → 5.0.5

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.
Files changed (154) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/ARCHITECTURE.md +0 -1
  4. package/CHANGELOG.md +110 -0
  5. package/INSTALL.md +0 -2
  6. package/README.md +1 -6
  7. package/bin/README.md +0 -1
  8. package/bin/cli/_install_helpers.py +1 -1
  9. package/bin/cli/approvals.py +23 -21
  10. package/bin/cli/cleanup.py +0 -1
  11. package/bin/cli/doctor.py +1 -1
  12. package/bin/cli/memory.py +2 -0
  13. package/bin/cli/update.py +1 -1
  14. package/bin/pre-publish-validate.js +48 -5
  15. package/config/README.md +22 -44
  16. package/config/surface-routing.json +0 -2
  17. package/dist/gaia-ops/.claude-plugin/plugin.json +1 -1
  18. package/dist/gaia-ops/config/README.md +22 -44
  19. package/dist/gaia-ops/config/surface-routing.json +0 -2
  20. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +18 -0
  21. package/dist/gaia-ops/hooks/modules/agents/handoff_persister.py +214 -2
  22. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +26 -0
  23. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +15 -0
  24. package/dist/gaia-ops/hooks/modules/security/__init__.py +0 -5
  25. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +124 -19
  26. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +99 -7
  27. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +127 -24
  28. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +90 -55
  29. package/dist/gaia-ops/skills/README.md +1 -1
  30. package/dist/gaia-ops/skills/agent-contract-handoff/SKILL.md +3 -0
  31. package/dist/gaia-ops/skills/agent-response/SKILL.md +4 -2
  32. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +1 -1
  33. package/dist/gaia-ops/skills/gaia-patterns/reference.md +2 -3
  34. package/dist/gaia-ops/skills/gaia-release/SKILL.md +60 -24
  35. package/dist/gaia-ops/skills/gaia-release/reference.md +35 -11
  36. package/dist/gaia-ops/skills/git-conventions/SKILL.md +6 -2
  37. package/dist/gaia-ops/skills/orchestrator-present-approval/SKILL.md +30 -7
  38. package/dist/gaia-ops/skills/orchestrator-present-approval/reference.md +32 -15
  39. package/dist/gaia-ops/skills/readme-writing/SKILL.md +1 -1
  40. package/dist/gaia-ops/skills/readme-writing/reference.md +0 -1
  41. package/dist/gaia-ops/skills/security-tiers/SKILL.md +5 -1
  42. package/dist/gaia-ops/skills/security-tiers/reference.md +3 -1
  43. package/dist/gaia-ops/skills/subagent-request-approval/SKILL.md +43 -6
  44. package/dist/gaia-ops/skills/subagent-request-approval/reference.md +66 -16
  45. package/dist/gaia-ops/tools/context/README.md +1 -1
  46. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +0 -1
  47. package/dist/gaia-ops/tools/scan/ui.py +20 -4
  48. package/dist/gaia-ops/tools/scan/verify.py +3 -3
  49. package/dist/gaia-ops/tools/validation/README.md +15 -24
  50. package/dist/gaia-security/.claude-plugin/plugin.json +1 -1
  51. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +18 -0
  52. package/dist/gaia-security/hooks/modules/agents/handoff_persister.py +214 -2
  53. package/dist/gaia-security/hooks/modules/agents/response_contract.py +26 -0
  54. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +15 -0
  55. package/dist/gaia-security/hooks/modules/security/__init__.py +0 -5
  56. package/dist/gaia-security/hooks/modules/security/approval_grants.py +124 -19
  57. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +99 -7
  58. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +127 -24
  59. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +90 -55
  60. package/gaia/state/transitions.py +4 -4
  61. package/gaia/store/writer.py +56 -0
  62. package/hooks/modules/README.md +2 -4
  63. package/hooks/modules/agents/contract_validator.py +18 -0
  64. package/hooks/modules/agents/handoff_persister.py +214 -2
  65. package/hooks/modules/agents/response_contract.py +26 -0
  66. package/hooks/modules/agents/transcript_reader.py +15 -0
  67. package/hooks/modules/security/__init__.py +0 -5
  68. package/hooks/modules/security/approval_grants.py +124 -19
  69. package/hooks/modules/security/mutative_verbs.py +99 -7
  70. package/hooks/modules/tools/bash_validator.py +127 -24
  71. package/hooks/modules/validation/commit_validator.py +90 -55
  72. package/index.js +2 -12
  73. package/package.json +4 -6
  74. package/pyproject.toml +3 -3
  75. package/scripts/bootstrap_database.sh +88 -439
  76. package/scripts/check_schema_drift.py +208 -0
  77. package/scripts/migrations/README.md +78 -28
  78. package/scripts/migrations/schema.checksum +8 -0
  79. package/scripts/release-prepare.mjs +199 -0
  80. package/skills/README.md +1 -1
  81. package/skills/agent-contract-handoff/SKILL.md +3 -0
  82. package/skills/agent-response/SKILL.md +4 -2
  83. package/skills/gaia-patterns/SKILL.md +1 -1
  84. package/skills/gaia-patterns/reference.md +2 -3
  85. package/skills/gaia-release/SKILL.md +60 -24
  86. package/skills/gaia-release/reference.md +35 -11
  87. package/skills/git-conventions/SKILL.md +6 -2
  88. package/skills/orchestrator-present-approval/SKILL.md +30 -7
  89. package/skills/orchestrator-present-approval/reference.md +32 -15
  90. package/skills/readme-writing/SKILL.md +1 -1
  91. package/skills/readme-writing/reference.md +0 -1
  92. package/skills/security-tiers/SKILL.md +5 -1
  93. package/skills/security-tiers/reference.md +3 -1
  94. package/skills/subagent-request-approval/SKILL.md +43 -6
  95. package/skills/subagent-request-approval/reference.md +66 -16
  96. package/tools/context/README.md +1 -1
  97. package/tools/gaia_simulator/extractor.py +0 -1
  98. package/tools/scan/ui.py +20 -4
  99. package/tools/scan/verify.py +3 -3
  100. package/tools/validation/README.md +15 -24
  101. package/commands/README.md +0 -64
  102. package/commands/gaia.md +0 -37
  103. package/commands/scan-project.md +0 -74
  104. package/config/crons-schema.md +0 -81
  105. package/config/git_standards.json +0 -72
  106. package/dist/gaia-ops/commands/gaia.md +0 -37
  107. package/dist/gaia-ops/config/crons-schema.md +0 -81
  108. package/dist/gaia-ops/config/git_standards.json +0 -72
  109. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +0 -179
  110. package/dist/gaia-ops/tools/agentic-loop/decide-status.py +0 -210
  111. package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +0 -106
  112. package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +0 -223
  113. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +0 -179
  114. package/git-hooks/commit-msg +0 -41
  115. package/hooks/modules/security/gitops_validator.py +0 -179
  116. package/scripts/migrations/v10_to_v11.sql +0 -170
  117. package/scripts/migrations/v10_to_v11_fresh.sql +0 -18
  118. package/scripts/migrations/v11_to_v12.sql +0 -195
  119. package/scripts/migrations/v11_to_v12_fresh.sql +0 -19
  120. package/scripts/migrations/v12_to_v13.sql +0 -48
  121. package/scripts/migrations/v12_to_v13_fresh.sql +0 -17
  122. package/scripts/migrations/v13_to_v14.sql +0 -44
  123. package/scripts/migrations/v13_to_v14_fresh.sql +0 -17
  124. package/scripts/migrations/v14_to_v15.sql +0 -71
  125. package/scripts/migrations/v14_to_v15_fresh.sql +0 -19
  126. package/scripts/migrations/v15_to_v16.sql +0 -57
  127. package/scripts/migrations/v15_to_v16_fresh.sql +0 -18
  128. package/scripts/migrations/v16_to_v17.sql +0 -51
  129. package/scripts/migrations/v16_to_v17_fresh.sql +0 -18
  130. package/scripts/migrations/v17_to_v18.sql +0 -66
  131. package/scripts/migrations/v17_to_v18_fresh.sql +0 -24
  132. package/scripts/migrations/v1_to_v2.sql +0 -97
  133. package/scripts/migrations/v2_to_v3.sql +0 -68
  134. package/scripts/migrations/v2_to_v3_merge.sql +0 -69
  135. package/scripts/migrations/v3_to_v4.sql +0 -67
  136. package/scripts/migrations/v3_to_v4_fresh.sql +0 -20
  137. package/scripts/migrations/v4_to_v5.sql +0 -55
  138. package/scripts/migrations/v4_to_v5_fresh.sql +0 -20
  139. package/scripts/migrations/v5_to_v6.sql +0 -48
  140. package/scripts/migrations/v5_to_v6_fresh.sql +0 -17
  141. package/scripts/migrations/v6_to_v7.sql +0 -26
  142. package/scripts/migrations/v6_to_v7_fresh.sql +0 -13
  143. package/scripts/migrations/v7_to_v8.sql +0 -44
  144. package/scripts/migrations/v7_to_v8_fresh.sql +0 -14
  145. package/scripts/migrations/v8_to_v9.sql +0 -87
  146. package/scripts/migrations/v8_to_v9_fresh.sql +0 -15
  147. package/scripts/migrations/v9_to_v10.sql +0 -109
  148. package/scripts/migrations/v9_to_v10_episodes_workspace.sql +0 -109
  149. package/scripts/migrations/v9_to_v10_fresh.sql +0 -18
  150. package/templates/README.md +0 -70
  151. package/templates/managed-settings.template.json +0 -43
  152. package/tools/agentic-loop/decide-status.py +0 -210
  153. package/tools/agentic-loop/parse-metric.py +0 -106
  154. package/tools/agentic-loop/record-iteration.py +0 -223
@@ -1,48 +0,0 @@
1
- -- Migration v5 -> v6 (evidence three-tier storage: dedicated evidence table).
2
- --
3
- -- Background
4
- -- ----------
5
- -- v5 schema has:
6
- -- acceptance_criteria(id, brief_id, ac_id, description, evidence_type,
7
- -- evidence_shape, artifact_path, status)
8
- -- milestones(id, brief_id, order_num, name, description, status)
9
- --
10
- -- v6 schema adds the evidence table for structured per-AC evidence storage.
11
- -- Each row is one evidence artifact tied to a brief_id + ac_id pair.
12
- -- Two storage modes:
13
- -- inline: text IS NOT NULL, artifact_path IS NULL (payload <= 4096 bytes)
14
- -- blob: text IS NULL, artifact_path IS NOT NULL (payload on filesystem)
15
- --
16
- -- Design decision: independent migration version
17
- -- ------------------------------------------------
18
- -- Evidence is an independent feature (Plan B). Extending v4_to_v5 with this
19
- -- DDL would have conflated two unrelated concerns in one migration version.
20
- -- The override decision (D4 of Plan A) establishes that each independent
21
- -- feature gets its own migration version -- evidence belongs in v6.
22
- --
23
- -- brief_id FK CASCADE ensures cleanup when a brief is deleted.
24
- -- type CHECK enforces the evidence taxonomy at the DB layer (new table,
25
- -- no rebuild penalty unlike the memory.class situation).
26
- --
27
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
28
- -- A failure mid-flight rolls back to v5 state and the ledger row is NOT
29
- -- inserted, so the next bootstrap retry sees the same pending migration.
30
-
31
- -- 1. Create the evidence table.
32
- CREATE TABLE IF NOT EXISTS evidence (
33
- id INTEGER PRIMARY KEY AUTOINCREMENT,
34
- brief_id INTEGER NOT NULL,
35
- ac_id TEXT NOT NULL,
36
- task_id TEXT,
37
- type TEXT NOT NULL CHECK (type IN ('text', 'file', 'command_output', 'url', 'screenshot')),
38
- text TEXT,
39
- artifact_path TEXT,
40
- size_bytes INTEGER,
41
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
42
- created_by_agent TEXT,
43
- FOREIGN KEY (brief_id) REFERENCES briefs(id) ON DELETE CASCADE
44
- );
45
-
46
- -- 2. Indexes to support brief-scoped and AC-scoped evidence queries.
47
- CREATE INDEX IF NOT EXISTS idx_evidence_brief ON evidence(brief_id);
48
- CREATE INDEX IF NOT EXISTS idx_evidence_ac ON evidence(brief_id, ac_id);
@@ -1,17 +0,0 @@
1
- -- v5 -> v6 fresh-install variant.
2
- --
3
- -- Used by bootstrap_database.sh Section 3c case 6 when the live DDL is
4
- -- already at the v6 target state (evidence table present). This happens on
5
- -- a clean install where schema.sql already created the evidence table.
6
- --
7
- -- The default v5_to_v6.sql cannot run here because CREATE TABLE IF NOT EXISTS
8
- -- is a no-op when the table already exists, but the indexes must still be
9
- -- stamped. This variant carries only the DDL that schema.sql cannot declare
10
- -- safely for older DBs:
11
- -- * idx_evidence_brief -- index on evidence(brief_id)
12
- -- * idx_evidence_ac -- index on evidence(brief_id, ac_id)
13
- --
14
- -- Both indexes are CREATE INDEX IF NOT EXISTS, making this script safe to re-run.
15
-
16
- CREATE INDEX IF NOT EXISTS idx_evidence_brief ON evidence(brief_id);
17
- CREATE INDEX IF NOT EXISTS idx_evidence_ac ON evidence(brief_id, ac_id);
@@ -1,26 +0,0 @@
1
- -- Migration v6 -> v7 (agent-contract-handoff M1: workspaces.last_scan_at)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v6 schema has:
6
- -- workspaces(name, identity, created_at)
7
- --
8
- -- v7 adds last_scan_at (ISO8601 TEXT, nullable) to workspaces.
9
- -- NULL means "never scanned via gaia scan" -- not 'pending'.
10
- -- The column is written by bin/cli/scan.py after a successful scan run.
11
- --
12
- -- Design decision: independent migration version
13
- -- -----------------------------------------------
14
- -- workspaces.last_scan_at is the first column added to workspaces.
15
- -- It belongs in v7, owned by the agent-contract-handoff brief (M1).
16
- -- M3 and M4 will add further columns in later v7 sub-tasks of the
17
- -- same migration file (both will extend this file in their dispatches).
18
- --
19
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
20
- -- A failure mid-flight rolls back to v6 state and the ledger row is NOT
21
- -- inserted, so the next bootstrap retry sees the same pending migration.
22
-
23
- -- 1. Add last_scan_at column to workspaces.
24
- -- SQLite ALTER TABLE ADD COLUMN is safe for nullable columns.
25
- ALTER TABLE workspaces ADD COLUMN last_scan_at TEXT;
26
-
@@ -1,13 +0,0 @@
1
- -- Migration v6 -> v7 fresh-install variant (agent-contract-handoff M1)
2
- --
3
- -- Used by bootstrap_database.sh when the live DB already has last_scan_at
4
- -- (i.e. schema.sql ran first on a clean install and created workspaces with
5
- -- the v7 column already present). This variant is a no-op -- it only exists
6
- -- so the bootstrap guard-probe branch can select it and stamp the ledger.
7
- --
8
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
9
- -- No DDL is executed; the COMMIT is harmless.
10
-
11
- -- No-op: column already exists on fresh install (schema.sql created it).
12
- -- This variant only exists to stamp the ledger without applying DDL.
13
- SELECT 1;
@@ -1,44 +0,0 @@
1
- -- Migration v7 -> v8 (agent-contract-handoff M3: approval_grants table)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v7 schema has:
6
- -- workspaces(name, identity, created_at, last_scan_at)
7
- --
8
- -- v8 adds the approval_grants table for DB-backed T3 command approval storage.
9
- -- This replaces the filesystem JSON approval store (.claude/cache/approvals/).
10
- -- Per D5 / D10: no TTL column (enforced at query time via created_at + 10 min);
11
- -- byte-for-byte command match; each command_set item is single-use.
12
- --
13
- -- Design decision: v8 bump (option a)
14
- -- ------------------------------------
15
- -- The approval_grants table was previously appended to v6_to_v7.sql as a
16
- -- supplemental idempotent block. That approach conflated two unrelated
17
- -- concerns in one migration version. v8 is the correct version for M3:
18
- -- each independent feature gets its own migration version (precedent from
19
- -- v5->v6 evidence table decision). The M3 appended block has been removed
20
- -- from v6_to_v7.sql and moved here.
21
- --
22
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
23
- -- A failure mid-flight rolls back to v7 state and the ledger row is NOT
24
- -- inserted, so the next bootstrap retry sees the same pending migration.
25
-
26
- -- 1. Create the approval_grants table.
27
- CREATE TABLE IF NOT EXISTS approval_grants (
28
- approval_id TEXT PRIMARY KEY, -- nonce, e.g. 32-char hex
29
- agent_id TEXT, -- agent that initiated the request
30
- session_id TEXT, -- CLAUDE_SESSION_ID at grant time
31
- command_set_json TEXT NOT NULL, -- JSON array of {command, rationale}
32
- scope TEXT NOT NULL DEFAULT 'COMMAND_SET', -- grant scope type
33
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
34
- expires_at TEXT, -- ISO8601 or NULL (TTL enforced at query time)
35
- status TEXT NOT NULL DEFAULT 'PENDING', -- PENDING|CONSUMED|REVOKED|EXPIRED
36
- consumed_indexes_json TEXT, -- JSON array of consumed command_set indexes
37
- consumed_at TEXT, -- ISO8601 when all items consumed
38
- revoked_at TEXT -- ISO8601 when explicitly revoked
39
- );
40
-
41
- -- 2. Indexes to support agent- and session-scoped approval queries.
42
- CREATE INDEX IF NOT EXISTS idx_approval_grants_agent ON approval_grants(agent_id);
43
- CREATE INDEX IF NOT EXISTS idx_approval_grants_session ON approval_grants(session_id);
44
- CREATE INDEX IF NOT EXISTS idx_approval_grants_status ON approval_grants(status);
@@ -1,14 +0,0 @@
1
- -- Migration v7 -> v8 fresh-install variant (agent-contract-handoff M3)
2
- --
3
- -- Used by bootstrap_database.sh when the live DB already has the approval_grants
4
- -- table (i.e. schema.sql ran first on a clean install and created the table
5
- -- in v8 target state already present). This variant is a no-op -- it only
6
- -- exists so the bootstrap guard-probe branch can select it and stamp the ledger.
7
- --
8
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
9
- -- No DDL is executed; the COMMIT is harmless.
10
-
11
- -- No-op: approval_grants table already exists on fresh install (schema.sql created it).
12
- -- The indexes are also created by schema.sql on fresh install.
13
- -- This variant only exists to stamp the ledger without applying DDL.
14
- SELECT 1;
@@ -1,87 +0,0 @@
1
- -- Migration v8 -> v9 (agent-contract-handoff M4: handoff persistence)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v8 schema has:
6
- -- approval_grants(approval_id, agent_id, session_id, command_set_json, ...)
7
- --
8
- -- v9 adds:
9
- -- agent_contract_handoffs -- persisted SubagentStop contract envelopes
10
- -- agent_contract_handoff_approvals -- approval decisions linked to handoffs
11
- -- project_context_contracts_history -- audit trail for PCC mutations
12
- -- trg_pcc_history -- AFTER UPDATE trigger on project_context_contracts
13
- --
14
- -- Design decisions
15
- -- ----------------
16
- -- * brief_id is NULLABLE -- subagents that return without a brief context
17
- -- still get a handoff row. EXTENSION_POINT for state-machine-completion:
18
- -- downstream briefs can query WHERE brief_id = <N> to verify completion
19
- -- invariants across the handoff record.
20
- -- * agent_contract_handoff_approvals CASCADE-deletes when the handoff row
21
- -- is removed. approval_id FK references approval_grants for audit integrity.
22
- -- * project_context_contracts_history captures before/after payloads at the
23
- -- SQL layer -- no Python path can bypass the trigger.
24
- --
25
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
26
- -- A failure mid-flight rolls back to v8 state; the ledger row is NOT
27
- -- inserted, so the next bootstrap retry sees the same pending migration.
28
-
29
- -- 1. Create the agent_contract_handoffs table.
30
- CREATE TABLE IF NOT EXISTS agent_contract_handoffs (
31
- id INTEGER PRIMARY KEY AUTOINCREMENT,
32
- agent_id TEXT NOT NULL, -- e.g. "a1b2c3d4e5"
33
- session_id TEXT, -- CLAUDE_SESSION_ID at SubagentStop time
34
- workspace TEXT NOT NULL, -- FK -> workspaces.name
35
- brief_id INTEGER, -- NULLABLE FK -> briefs.id; EXTENSION_POINT
36
- task_status TEXT NOT NULL, -- resolved plan_status from contract envelope
37
- raw_handoff_json TEXT NOT NULL, -- full contract envelope serialized
38
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
39
- FOREIGN KEY (workspace) REFERENCES workspaces(name),
40
- FOREIGN KEY (brief_id) REFERENCES briefs(id)
41
- );
42
-
43
- CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_workspace ON agent_contract_handoffs(workspace);
44
- CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_brief ON agent_contract_handoffs(brief_id);
45
- CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_session ON agent_contract_handoffs(session_id);
46
-
47
- -- 2. Create the agent_contract_handoff_approvals table.
48
- CREATE TABLE IF NOT EXISTS agent_contract_handoff_approvals (
49
- id INTEGER PRIMARY KEY AUTOINCREMENT,
50
- handoff_id INTEGER NOT NULL, -- FK -> agent_contract_handoffs.id
51
- approval_id TEXT NOT NULL, -- FK -> approval_grants.approval_id
52
- decision TEXT NOT NULL CHECK (decision IN ('APPROVED', 'REJECTED', 'EXPIRED', 'REVOKED')),
53
- decided_at TEXT NOT NULL,
54
- FOREIGN KEY (handoff_id) REFERENCES agent_contract_handoffs(id) ON DELETE CASCADE,
55
- FOREIGN KEY (approval_id) REFERENCES approval_grants(approval_id)
56
- );
57
-
58
- CREATE INDEX IF NOT EXISTS idx_agent_contract_handoff_approvals_handoff ON agent_contract_handoff_approvals(handoff_id);
59
-
60
- -- 3. Create the project_context_contracts_history table.
61
- CREATE TABLE IF NOT EXISTS project_context_contracts_history (
62
- id INTEGER PRIMARY KEY AUTOINCREMENT,
63
- contract_key TEXT NOT NULL, -- project_context_contracts.contract_key
64
- workspace TEXT NOT NULL, -- FK -> workspaces.name
65
- before_payload_json TEXT, -- NULL on first insert (no prior value)
66
- after_payload_json TEXT NOT NULL, -- new payload value
67
- changed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
68
- changed_by_agent TEXT, -- optional: GAIA_DISPATCH_AGENT at write time
69
- FOREIGN KEY (workspace) REFERENCES workspaces(name)
70
- );
71
-
72
- CREATE INDEX IF NOT EXISTS idx_pcc_history_contract ON project_context_contracts_history(contract_key);
73
-
74
- -- 4. Create the AFTER UPDATE trigger on project_context_contracts.
75
- CREATE TRIGGER IF NOT EXISTS trg_pcc_history
76
- AFTER UPDATE ON project_context_contracts
77
- BEGIN
78
- INSERT INTO project_context_contracts_history (
79
- contract_key, workspace, before_payload_json, after_payload_json, changed_at
80
- ) VALUES (
81
- OLD.contract_key,
82
- OLD.workspace,
83
- OLD.payload_json,
84
- NEW.payload_json,
85
- strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
86
- );
87
- END;
@@ -1,15 +0,0 @@
1
- -- Migration v8 -> v9 fresh-install variant (agent-contract-handoff M4)
2
- --
3
- -- Used by bootstrap_database.sh when the live DB already has the
4
- -- agent_contract_handoffs table (i.e. schema.sql ran first on a clean
5
- -- install and created the tables in v9 target state).
6
- --
7
- -- This variant is a no-op -- it only exists so the bootstrap guard-probe
8
- -- branch can select it and stamp the ledger without applying DDL.
9
- --
10
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
11
- -- No DDL is executed; the COMMIT is harmless.
12
-
13
- -- No-op: all v9 tables and trigger already exist on fresh install (schema.sql).
14
- -- This variant only exists to stamp the ledger.
15
- SELECT 1;
@@ -1,109 +0,0 @@
1
- -- Migration v9 -> v10 (episodic-workflow-to-db: episodes workspace canonical)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v9 schema has the episodes table with these columns:
6
- -- episode_id, workspace, timestamp, session_id, task_id, agent,
7
- -- type, title, prompt, enriched_prompt, wf_prompt, clarifications,
8
- -- keywords, tags, commands_executed, context_metrics, relevance_score,
9
- -- outcome, duration_seconds, exit_code, plan_status, output_length,
10
- -- output_tokens_approx
11
- --
12
- -- v10 adds:
13
- -- episodes.tier -- security tier (T0/T1/T2/T3), promoted from context_metrics blob
14
- -- episode_anomalies -- structured anomaly records extracted from context_metrics blob
15
- --
16
- -- Design decisions
17
- -- ----------------
18
- -- D1: tier -> top-level column (not blob)
19
- -- Rationale: tier is a single short TEXT value (T0/T1/T2/T3) with a clear
20
- -- compliance query pattern: "COUNT(*) WHERE tier='T3' AND outcome='partial'".
21
- -- Keeping it in the context_metrics JSON blob would require a full-table
22
- -- JSON parse for every compliance query. With 10,000+ rows in workspace 'me'
23
- -- alone, this is a significant performance cost. A column + index reduces
24
- -- that to a B-tree lookup. The schema cost is one ALTER TABLE + one index.
25
- -- Alternative considered: keep in blob. Rejected because the query pattern
26
- -- is both real (used by context_injector.py anomaly surfacing) and frequent
27
- -- (every compliance dashboard query). No reason to pay JSON parsing overhead
28
- -- when the data is a four-value enum.
29
- --
30
- -- D2: episode_anomalies -> separate table (not blob)
31
- -- Rationale: anomalies have a stable schema {type, severity, message} per
32
- -- object. The query "all anomalies of type X in the last 7 days" is a real
33
- -- operational need -- context_injector.py currently reads anomalies.jsonl
34
- -- to surface critical anomalies in orchestrator context. That reader must
35
- -- be ported post-migration. A separate table with a type index enables
36
- -- `SELECT * FROM episode_anomalies JOIN episodes ON ... WHERE type=? AND
37
- -- episodes.timestamp > ?` without JSON parsing any rows. With anomalies
38
- -- present in a large fraction of episodes (4 anomalies in the 12 observed
39
- -- sessions), the cardinality justifies a separate table. The anomalies[]
40
- -- array is still preserved inside context_metrics for backward compatibility
41
- -- with any reader that parses the full blob -- the table is an additional
42
- -- queryable index, not a replacement.
43
- -- Alternative considered: keep in context_metrics blob. Rejected because
44
- -- the type-filtered cross-episode query has no efficient implementation
45
- -- without the table. GROUP BY type reports are otherwise O(N) full scans
46
- -- with JSON parsing per row.
47
- --
48
- -- Column notes
49
- -- ------------
50
- -- episodes.workspace: already present in the v9 schema; NO ALTER TABLE needed.
51
- -- Live DB confirmed: workspace column exists and has data ('me', 'bildwiz',
52
- -- 'nfi'). The default 'me' for legacy rows is unnecessary -- workspace is
53
- -- already populated. This step is a no-op in terms of DDL.
54
- --
55
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
56
- -- A failure mid-flight rolls back to v9 state; the ledger row is NOT
57
- -- inserted, so the next bootstrap retry sees the same pending migration.
58
- -- Closes AC-2 of brief episodic-workflow-to-db (brief_id=72).
59
-
60
- -- Step 1: Add tier column to episodes.
61
- -- SQLite does not support CHECK constraints in ALTER TABLE ADD COLUMN without
62
- -- a DEFAULT, so the CHECK is omitted here; validation is enforced at the
63
- -- application layer (episodic.py / workflow_recorder.py writers).
64
- ALTER TABLE episodes ADD COLUMN tier TEXT;
65
-
66
- -- Step 2: Index tier for compliance queries.
67
- CREATE INDEX IF NOT EXISTS idx_episodes_tier ON episodes(tier);
68
-
69
- -- Step 3: Compound index for the primary compliance query pattern:
70
- -- "T3 operations with non-COMPLETE outcomes in time window".
71
- CREATE INDEX IF NOT EXISTS idx_episodes_tier_outcome ON episodes(tier, outcome);
72
-
73
- -- Step 4: Create episode_anomalies table.
74
- -- Each row is one anomaly record extracted from an episode's context_metrics
75
- -- blob. The payload column holds the full original JSON object for forward
76
- -- compatibility (additional keys in future anomaly schemas are preserved).
77
- CREATE TABLE IF NOT EXISTS episode_anomalies (
78
- id INTEGER PRIMARY KEY AUTOINCREMENT,
79
- episode_id TEXT NOT NULL, -- FK -> episodes.episode_id
80
- workspace TEXT NOT NULL, -- denormalized for partition queries without JOIN
81
- timestamp TEXT NOT NULL, -- denormalized from parent episode for time-range queries
82
- type TEXT NOT NULL, -- e.g. "investigation_skip", "no_tool_use"
83
- severity TEXT, -- e.g. "warning", "error", "info"
84
- message TEXT, -- human-readable description
85
- payload TEXT, -- full JSON object (forward-compat for extra keys)
86
- FOREIGN KEY (episode_id) REFERENCES episodes(episode_id) ON DELETE CASCADE
87
- );
88
-
89
- -- Step 5: Indexes on episode_anomalies.
90
- -- Primary query patterns:
91
- -- (a) All anomalies of type X: WHERE type = ?
92
- -- (b) Cross-episode anomaly report in time window: WHERE type = ? AND timestamp > ?
93
- -- (c) Anomalies for a specific episode: WHERE episode_id = ?
94
- -- (d) Workspace-scoped anomaly dashboard: WHERE workspace = ? AND timestamp > ?
95
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_type ON episode_anomalies(type);
96
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_workspace ON episode_anomalies(workspace, timestamp DESC);
97
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_episode ON episode_anomalies(episode_id);
98
-
99
- -- Step 6: Bump schema_version to 10.
100
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
101
- VALUES (10, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
102
- 'episodes.tier column + idx + episode_anomalies table (brief episodic-workflow-to-db AC-2)');
103
-
104
- -- Verification queries (run after applying):
105
- -- SELECT MAX(version) FROM schema_version; -- expect: 10
106
- -- PRAGMA table_info(episodes); -- expect: tier column present (after output_tokens_approx)
107
- -- SELECT * FROM sqlite_master WHERE type='index' AND name LIKE 'idx_episodes_tier%'; -- expect: 2 rows
108
- -- PRAGMA table_info(episode_anomalies); -- expect: 7 columns
109
- -- SELECT COUNT(*) FROM episode_anomalies; -- expect: 0 (populated by T3 migration task)
@@ -1,109 +0,0 @@
1
- -- Migration v9 -> v10 (episodic-workflow-to-db: episodes workspace canonical)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v9 schema has the episodes table with these columns:
6
- -- episode_id, workspace, timestamp, session_id, task_id, agent,
7
- -- type, title, prompt, enriched_prompt, wf_prompt, clarifications,
8
- -- keywords, tags, commands_executed, context_metrics, relevance_score,
9
- -- outcome, duration_seconds, exit_code, plan_status, output_length,
10
- -- output_tokens_approx
11
- --
12
- -- v10 adds:
13
- -- episodes.tier -- security tier (T0/T1/T2/T3), promoted from context_metrics blob
14
- -- episode_anomalies -- structured anomaly records extracted from context_metrics blob
15
- --
16
- -- Design decisions
17
- -- ----------------
18
- -- D1: tier -> top-level column (not blob)
19
- -- Rationale: tier is a single short TEXT value (T0/T1/T2/T3) with a clear
20
- -- compliance query pattern: "COUNT(*) WHERE tier='T3' AND outcome='partial'".
21
- -- Keeping it in the context_metrics JSON blob would require a full-table
22
- -- JSON parse for every compliance query. With 10,000+ rows in workspace 'me'
23
- -- alone, this is a significant performance cost. A column + index reduces
24
- -- that to a B-tree lookup. The schema cost is one ALTER TABLE + one index.
25
- -- Alternative considered: keep in blob. Rejected because the query pattern
26
- -- is both real (used by context_injector.py anomaly surfacing) and frequent
27
- -- (every compliance dashboard query). No reason to pay JSON parsing overhead
28
- -- when the data is a four-value enum.
29
- --
30
- -- D2: episode_anomalies -> separate table (not blob)
31
- -- Rationale: anomalies have a stable schema {type, severity, message} per
32
- -- object. The query "all anomalies of type X in the last 7 days" is a real
33
- -- operational need -- context_injector.py currently reads anomalies.jsonl
34
- -- to surface critical anomalies in orchestrator context. That reader must
35
- -- be ported post-migration. A separate table with a type index enables
36
- -- `SELECT * FROM episode_anomalies JOIN episodes ON ... WHERE type=? AND
37
- -- episodes.timestamp > ?` without JSON parsing any rows. With anomalies
38
- -- present in a large fraction of episodes (4 anomalies in the 12 observed
39
- -- sessions), the cardinality justifies a separate table. The anomalies[]
40
- -- array is still preserved inside context_metrics for backward compatibility
41
- -- with any reader that parses the full blob -- the table is an additional
42
- -- queryable index, not a replacement.
43
- -- Alternative considered: keep in context_metrics blob. Rejected because
44
- -- the type-filtered cross-episode query has no efficient implementation
45
- -- without the table. GROUP BY type reports are otherwise O(N) full scans
46
- -- with JSON parsing per row.
47
- --
48
- -- Column notes
49
- -- ------------
50
- -- episodes.workspace: already present in the v9 schema; NO ALTER TABLE needed.
51
- -- Live DB confirmed: workspace column exists and has data ('me', 'bildwiz',
52
- -- 'nfi'). The default 'me' for legacy rows is unnecessary -- workspace is
53
- -- already populated. This step is a no-op in terms of DDL.
54
- --
55
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
56
- -- A failure mid-flight rolls back to v9 state; the ledger row is NOT
57
- -- inserted, so the next bootstrap retry sees the same pending migration.
58
- -- Closes AC-2 of brief episodic-workflow-to-db (brief_id=72).
59
-
60
- -- Step 1: Add tier column to episodes.
61
- -- SQLite does not support CHECK constraints in ALTER TABLE ADD COLUMN without
62
- -- a DEFAULT, so the CHECK is omitted here; validation is enforced at the
63
- -- application layer (episodic.py / workflow_recorder.py writers).
64
- ALTER TABLE episodes ADD COLUMN tier TEXT;
65
-
66
- -- Step 2: Index tier for compliance queries.
67
- CREATE INDEX IF NOT EXISTS idx_episodes_tier ON episodes(tier);
68
-
69
- -- Step 3: Compound index for the primary compliance query pattern:
70
- -- "T3 operations with non-COMPLETE outcomes in time window".
71
- CREATE INDEX IF NOT EXISTS idx_episodes_tier_outcome ON episodes(tier, outcome);
72
-
73
- -- Step 4: Create episode_anomalies table.
74
- -- Each row is one anomaly record extracted from an episode's context_metrics
75
- -- blob. The payload column holds the full original JSON object for forward
76
- -- compatibility (additional keys in future anomaly schemas are preserved).
77
- CREATE TABLE IF NOT EXISTS episode_anomalies (
78
- id INTEGER PRIMARY KEY AUTOINCREMENT,
79
- episode_id TEXT NOT NULL, -- FK -> episodes.episode_id
80
- workspace TEXT NOT NULL, -- denormalized for partition queries without JOIN
81
- timestamp TEXT NOT NULL, -- denormalized from parent episode for time-range queries
82
- type TEXT NOT NULL, -- e.g. "investigation_skip", "no_tool_use"
83
- severity TEXT, -- e.g. "warning", "error", "info"
84
- message TEXT, -- human-readable description
85
- payload TEXT, -- full JSON object (forward-compat for extra keys)
86
- FOREIGN KEY (episode_id) REFERENCES episodes(episode_id) ON DELETE CASCADE
87
- );
88
-
89
- -- Step 5: Indexes on episode_anomalies.
90
- -- Primary query patterns:
91
- -- (a) All anomalies of type X: WHERE type = ?
92
- -- (b) Cross-episode anomaly report in time window: WHERE type = ? AND timestamp > ?
93
- -- (c) Anomalies for a specific episode: WHERE episode_id = ?
94
- -- (d) Workspace-scoped anomaly dashboard: WHERE workspace = ? AND timestamp > ?
95
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_type ON episode_anomalies(type);
96
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_workspace ON episode_anomalies(workspace, timestamp DESC);
97
- CREATE INDEX IF NOT EXISTS idx_episode_anomalies_episode ON episode_anomalies(episode_id);
98
-
99
- -- Step 6: Bump schema_version to 10.
100
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
101
- VALUES (10, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
102
- 'episodes.tier column + idx + episode_anomalies table (brief episodic-workflow-to-db AC-2)');
103
-
104
- -- Verification queries (run after applying):
105
- -- SELECT MAX(version) FROM schema_version; -- expect: 10
106
- -- PRAGMA table_info(episodes); -- expect: tier column present (after output_tokens_approx)
107
- -- SELECT * FROM sqlite_master WHERE type='index' AND name LIKE 'idx_episodes_tier%'; -- expect: 2 rows
108
- -- PRAGMA table_info(episode_anomalies); -- expect: 7 columns
109
- -- SELECT COUNT(*) FROM episode_anomalies; -- expect: 0 (populated by T3 migration task)
@@ -1,18 +0,0 @@
1
- -- Migration v9 -> v10 fresh-install variant (episodic-workflow-to-db AC-3)
2
- --
3
- -- Used by bootstrap_database.sh when the live DB already has the
4
- -- episode_anomalies table (i.e. schema.sql ran first on a clean install and
5
- -- created the tables in v10 target state, including episodes.tier column).
6
- --
7
- -- On a fresh install, schema.sql creates the episodes table WITH the tier
8
- -- column, so ALTER TABLE is not needed. However, the tier-dependent indexes
9
- -- (idx_episodes_tier, idx_episodes_tier_outcome) cannot be declared in
10
- -- schema.sql because schema.sql runs before migrations on existing DBs where
11
- -- tier does not yet exist. This fresh variant creates those indexes safely,
12
- -- since on a fresh install tier is guaranteed to exist.
13
- --
14
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
15
-
16
- -- Create tier indexes that schema.sql cannot safely declare for existing DBs.
17
- CREATE INDEX IF NOT EXISTS idx_episodes_tier ON episodes(tier);
18
- CREATE INDEX IF NOT EXISTS idx_episodes_tier_outcome ON episodes(tier, outcome);
@@ -1,70 +0,0 @@
1
- # Templates
2
-
3
- Templates are the reference files that Gaia uses to generate per-project configuration. They are not consumed by the Claude Code runtime — they are consumed by the install scripts in `bin/` and by organization administrators deploying managed policies. Think of this directory as the catalog of files that exist as skeletons, ready to be filled in during installation or deployed verbatim as a policy.
4
-
5
- There are two audiences for this directory, and they do not overlap. The first is the individual developer installing Gaia into their project — `gaia install` (run by the npm postinstall hook) bootstraps the DB and `.claude/` structure. The second is the enterprise administrator — they take `managed-settings.template.json` and deploy it as a managed policy via the Claude.ai Admin Console or by placing it at `/etc/claude-code/managed-settings.json` on managed workstations. `gaia scan` (separate from install) writes project context to `~/.gaia/gaia.db` only; it does not read or interpolate templates.
6
-
7
- Keeping these files here, rather than embedding them in `bin/cli/scan.py`, means policies and skeletons can be audited and customized without touching executable code. An admin can diff `managed-settings.template.json` against a previous version. A developer can read `governance.template.md` (when present) before letting the scanner interpolate it.
8
-
9
- ## Cuándo se activa
10
-
11
- This component does not activate in the runtime Claude Code pipeline. Templates are consumed only by install-time tooling and by administrators deploying policies out-of-band.
12
-
13
- **When each template is consumed:**
14
-
15
- ```
16
- Individual developer runs: npm install @jaguilar87/gaia
17
- |
18
- postinstall -> gaia install --postinstall
19
- |
20
- Install bootstraps ~/.gaia/gaia.db, creates .claude/ symlinks, merges settings.
21
- Templates in this directory are NOT read during install or scan.
22
-
23
- Developer separately runs: gaia scan
24
- |
25
- bin/cli/scan.py detects project stack and writes to ~/.gaia/gaia.db.
26
- gaia scan does NOT read templates/ or generate any files.
27
- ```
28
-
29
- ```
30
- Enterprise admin deploys managed policy
31
- |
32
- Admin copies templates/managed-settings.template.json
33
- |
34
- Deploys to Claude.ai Admin Console
35
- OR writes to /etc/claude-code/managed-settings.json (Linux managed workstations)
36
- |
37
- Managed settings take highest precedence — cannot be overridden by user or project
38
- ```
39
-
40
- ## Qué hay aquí
41
-
42
- ```
43
- templates/
44
- ├── managed-settings.template.json # Enterprise reference — deployed by admin, not gaia-scan
45
- └── README.md
46
- ```
47
-
48
- Currently only `managed-settings.template.json` ships in this directory. A `governance.template.md` has been referenced in prior docs but is not present in source and is not consumed by any current automated step (`gaia scan` writes to DB only; `gaia install` does not interpolate templates). If a future installer step consumes templates, this note should be updated.
49
-
50
- ## Convenciones
51
-
52
- **Audience per file:**
53
-
54
- | File | Audience | Consumed by | Trigger |
55
- |------|----------|-------------|---------|
56
- | `managed-settings.template.json` | Enterprise administrator | Claude.ai Admin Console or `/etc/claude-code/managed-settings.json` | Admin action — out of band, not automated |
57
- | `governance.template.md` (if present) | Individual developer | Future install tooling (not yet implemented) | Not currently consumed by any automated step |
58
-
59
- **Managed settings precedence:** `managed-settings.template.json` contains wildcard deny rules that cannot be overridden by user or project settings. It also sets `disableBypassPermissionsMode: true` to prevent `--dangerously-skip-permissions`. Deploy this only when you want organization-wide enforcement.
60
-
61
- **No CLAUDE.md generated:** Orchestrator identity is no longer generated from a template. It lives in `agents/gaia-orchestrator.md` and is activated via `settings.json: { "agent": "gaia-orchestrator" }`. Surface routing is injected by the `UserPromptSubmit` hook, not by a template.
62
-
63
- **Template naming:** Files intended for interpolation use the `.template.<ext>` suffix (e.g., `governance.template.md`, `managed-settings.template.json`). Files without that suffix should not be here.
64
-
65
- ## Ver también
66
-
67
- - [`bin/cli/install.py`](../bin/cli/install.py) — `gaia install` (postinstall) bootstraps the DB and `.claude/` structure; templates are not currently read by any automated step
68
- - [`bin/cli/update.py`](../bin/cli/update.py) — `gaia update` updates settings.local.json (merges, does not use templates here)
69
- - [`agents/gaia-orchestrator.md`](../agents/gaia-orchestrator.md) — orchestrator identity (replaces old CLAUDE.md template path)
70
- - [`build/gaia-ops.manifest.json`](../build/gaia-ops.manifest.json) — plugin-level permission defaults (distinct from managed-settings)
@@ -1,43 +0,0 @@
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
- }