Files
cleveragents-core/docs/reference/changeset.md
T
HAL9000 18d00c04c4
CI / lint (pull_request) Failing after 1m15s
CI / quality (pull_request) Successful in 1m21s
CI / typecheck (pull_request) Successful in 1m34s
CI / security (pull_request) Successful in 1m37s
CI / coverage (pull_request) Has been skipped
CI / unit_tests (pull_request) Failing after 1m37s
CI / docker (pull_request) Has been skipped
CI / build (pull_request) Successful in 33s
CI / helm (pull_request) Successful in 26s
CI / push-validation (pull_request) Successful in 19s
CI / e2e_tests (pull_request) Successful in 3m20s
CI / integration_tests (pull_request) Successful in 4m32s
CI / status-check (pull_request) Failing after 3s
fix(skills): implement multi-scope agent skill discovery for global, project, and local tiers
Implements AgentSkillDiscovery class to support discovering Agent Skills from
multiple configured directories across three scopes (global, project, local).
Handles name collisions with precedence: local > project > global.

Adds comprehensive BDD test coverage for multi-scope discovery scenarios including:
- Global-only, project-only, and local-only discovery
- Combined discovery from all scopes
- Name collision resolution with proper precedence
- Non-existent and empty scope directory handling
- Multiple skills in same scope discovery

ISSUES CLOSED: #9369
2026-05-06 19:55:22 +00:00

5.0 KiB

ChangeSet Persistence

Overview

ChangeSets track every file mutation made during the Execute phase of a plan. Each mutation is recorded as a ChangeEntry with content hashes, operation type, and tool provenance. Tool executions are recorded as ToolInvocation records for full auditability.

Persistence Fields

changeset_entries table

Column Type Description
entry_id String(26) ULID primary key
changeset_id String(26) ULID of the owning changeset
plan_id String(26) ULID of the owning plan
resource_id String(26) ULID of the affected resource
tool_name String(255) Namespaced tool name
operation String(20) create, modify, delete, or rename
path String(1024) Repo-relative file path
before_hash String(64) SHA-256 before change (nullable)
after_hash String(64) SHA-256 after change (nullable)
before_mode Integer File mode before change (nullable)
after_mode Integer File mode after change (nullable)
timestamp String(30) ISO-8601 UTC timestamp

tool_invocations table

Column Type Description
invocation_id String(26) ULID primary key
changeset_id String(26) Optional owning changeset
plan_id String(26) Owning plan ULID
tool_name String(255) Namespaced tool name
skill_name String(255) Skill that provided the tool
arguments_json Text JSON input parameters
result_json Text JSON output payload
error Text Error message on failure
success Boolean Whether execution succeeded
duration_ms Float Execution time in milliseconds
started_at String(30) ISO-8601 start timestamp
completed_at String(30) ISO-8601 completion timestamp
change_ids_json Text JSON list of ChangeEntry IDs
sequence_number Integer Ordering within a plan
sandbox_path String(1024) Sandbox root path
resource_refs_json Text JSON list of resource IDs
provider_metadata_json Text JSON provider info

Diff Output Examples

Plain format (agents plan diff <plan_id> --format plain)

ChangeSet: 01HXYZ123456789ABCDEFG
Plan: 01HABCDEF123456789XYZ
Total changes: 3

--- a/src/new_module.py
+++ b/src/new_module.py
@@ new file @@
+ hash: abc123def456...

--- a/src/existing.py
+++ b/src/existing.py
@@ modified @@
- hash: old_hash_val...
+ hash: new_hash_val...

--- a/src/removed.py
+++ b/src/removed.py
@@ deleted @@
- hash: file_hash_be...

JSON format (agents plan diff <plan_id> --format json)

{
  "changeset_id": "01HXYZ123456789ABCDEFG",
  "plan_id": "01HABCDEF123456789XYZ",
  "total_changes": 3,
  "summary": {
    "total": 3,
    "creates": 1,
    "modifies": 1,
    "deletes": 1,
    "renames": 0,
    "paths_changed": 3,
    "resources_involved": 1
  },
  "entries": [
    {
      "path": "src/new_module.py",
      "operation": "create",
      "before_hash": null,
      "after_hash": "abc123def456",
      "resource_id": "01HRES001",
      "tool_name": "file-write",
      "timestamp": "2026-02-24T12:00:00+00:00"
    }
  ]
}

Artifacts output (agents plan artifacts <plan_id>)

{
  "plan_id": "01HABCDEF123456789XYZ",
  "phase": "execute",
  "processing_state": "complete",
  "changeset_id": "01HXYZ123456789ABCDEFG",
  "sandbox_refs": ["sandbox-001"],
  "changeset_summary": {
    "total": 3,
    "creates": 1,
    "modifies": 1,
    "deletes": 1,
    "renames": 0
  },
  "files_changed": [
    {"path": "src/new_module.py", "operation": "create"},
    {"path": "src/existing.py", "operation": "modify"},
    {"path": "src/removed.py", "operation": "delete"}
  ]
}

Cleanup Behaviour

Changeset artifacts are automatically cleaned up when:

  • Plan cancel: cleanup_changeset() deletes all persisted entries and invocations for the cancelled plan.
  • Apply failure: cleanup_changeset() is called after handle_merge_failure() to free storage for failed plans.

API

SqliteChangeSetStore

Implements the ChangeSetStore protocol with SQLite persistence.

from cleveragents.infrastructure.database.changeset_repository import (
    SqliteChangeSetStore,
)

store = SqliteChangeSetStore(session_factory)
changeset_id = store.start(plan_id)
store.record(changeset_id, entry)
changeset = store.get(changeset_id)
store.delete_for_plan(plan_id)