@sdotwinter/openclaw-deterministic 0.17.5 → 0.17.8
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/LICENSE +1 -1
- package/README.md +72 -40
- package/ROADMAP.md +81 -0
- package/bin/audit.js +25 -1
- package/bin/upgrade.js +81 -16
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# OpenClaw Deterministic
|
|
1
|
+
# OpenClaw Deterministic (OCD)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Deterministic governance, memory discipline, and integrity enforcement framework for OpenClaw.
|
|
4
4
|
|
|
5
|
-
OpenClaw Deterministic
|
|
5
|
+
OpenClaw Deterministic transforms OpenClaw into a predictable, auditable execution system suitable for long-running agent deployments and CI environments.
|
|
6
6
|
|
|
7
7
|
This is not an assistant plugin.
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ Install globally:
|
|
|
16
16
|
|
|
17
17
|
npm install -g @sdotwinter/openclaw-deterministic
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Apply deterministic governance to an existing OpenClaw workspace:
|
|
20
20
|
|
|
21
21
|
oc-deterministic install
|
|
22
22
|
|
|
@@ -24,22 +24,39 @@ Verify installation:
|
|
|
24
24
|
|
|
25
25
|
oc-deterministic doctor
|
|
26
26
|
|
|
27
|
-
Concise health summary:
|
|
27
|
+
Concise health summary (CI-friendly):
|
|
28
28
|
|
|
29
29
|
oc-deterministic status
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
|
+
## Safety Guarantees
|
|
34
|
+
|
|
35
|
+
OpenClaw Deterministic enforces execution discipline with explicit safety guarantees:
|
|
36
|
+
|
|
37
|
+
- Does not overwrite an existing SOUL.md
|
|
38
|
+
- Verifies canonical integrity before upgrade
|
|
39
|
+
- Refuses to upgrade drifted files (unless --force)
|
|
40
|
+
- Creates deterministic backup snapshots before mutation
|
|
41
|
+
- Supports structured revert to previous snapshot
|
|
42
|
+
- Exposes machine-readable health status
|
|
43
|
+
- Blocks silent structural mutation
|
|
44
|
+
|
|
45
|
+
This system assumes drift is inevitable.
|
|
46
|
+
|
|
47
|
+
It makes drift visible.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
33
51
|
## What This Solves
|
|
34
52
|
|
|
35
|
-
AI systems drift
|
|
53
|
+
AI systems drift over time:
|
|
36
54
|
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
- Execution
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
- Contract integrity
|
|
55
|
+
- Memory growth
|
|
56
|
+
- File mutation
|
|
57
|
+
- Execution misclassification
|
|
58
|
+
- Configuration divergence
|
|
59
|
+
- Contract ambiguity
|
|
43
60
|
|
|
44
61
|
OpenClaw Deterministic enforces:
|
|
45
62
|
|
|
@@ -48,9 +65,9 @@ OpenClaw Deterministic enforces:
|
|
|
48
65
|
- Semantic memory limits
|
|
49
66
|
- Config-driven thresholds
|
|
50
67
|
- Governance event logging
|
|
51
|
-
- Structured
|
|
68
|
+
- Structured health reporting
|
|
52
69
|
|
|
53
|
-
The
|
|
70
|
+
The objective:
|
|
54
71
|
|
|
55
72
|
Predictable execution under defined constraints.
|
|
56
73
|
|
|
@@ -60,14 +77,15 @@ Predictable execution under defined constraints.
|
|
|
60
77
|
|
|
61
78
|
### Deterministic Execution Tiers
|
|
62
79
|
|
|
63
|
-
Execution is classified into
|
|
80
|
+
Execution is classified into:
|
|
64
81
|
|
|
65
82
|
Tier A — Safe
|
|
66
83
|
Tier B — Governed Modification
|
|
67
84
|
Tier C — Destructive / Structural
|
|
68
85
|
|
|
69
86
|
Each tier defines:
|
|
70
|
-
|
|
87
|
+
|
|
88
|
+
- Whether a diff preview is required
|
|
71
89
|
- Whether confirmation is required
|
|
72
90
|
- Whether auto-execution is allowed
|
|
73
91
|
|
|
@@ -79,7 +97,7 @@ This prevents silent behavioral drift.
|
|
|
79
97
|
|
|
80
98
|
Deterministic templates embed canonical SHA256 hashes.
|
|
81
99
|
|
|
82
|
-
|
|
100
|
+
doctor verifies:
|
|
83
101
|
|
|
84
102
|
- Template presence
|
|
85
103
|
- Version alignment
|
|
@@ -87,7 +105,39 @@ Deterministic templates embed canonical SHA256 hashes.
|
|
|
87
105
|
|
|
88
106
|
If a file is manually edited outside deterministic flow, the system detects it.
|
|
89
107
|
|
|
90
|
-
|
|
108
|
+
Tamper visibility is enforced.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### Upgrade Integrity Gate
|
|
113
|
+
|
|
114
|
+
oc-deterministic upgrade:
|
|
115
|
+
|
|
116
|
+
- Verifies canonical integrity before applying changes
|
|
117
|
+
- Refuses overwrite if drift is detected
|
|
118
|
+
- Supports --force override
|
|
119
|
+
- Supports --dry-run
|
|
120
|
+
|
|
121
|
+
Upgrade is governed mutation — not blind overwrite.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### Deterministic Backup + Revert
|
|
126
|
+
|
|
127
|
+
Before template mutation:
|
|
128
|
+
|
|
129
|
+
Snapshots are stored at:
|
|
130
|
+
|
|
131
|
+
~/.openclaw/backups/deterministic/<timestamp>/
|
|
132
|
+
|
|
133
|
+
Revert commands:
|
|
134
|
+
|
|
135
|
+
oc-deterministic revert --list
|
|
136
|
+
oc-deterministic revert --to <timestamp>
|
|
137
|
+
|
|
138
|
+
Revert restores deterministic files from snapshot.
|
|
139
|
+
|
|
140
|
+
This enables safe experimentation without state loss.
|
|
91
141
|
|
|
92
142
|
---
|
|
93
143
|
|
|
@@ -100,7 +150,7 @@ Semantic memory is:
|
|
|
100
150
|
- Evaluated against risk thresholds
|
|
101
151
|
- Logged on violation
|
|
102
152
|
|
|
103
|
-
Configuration:
|
|
153
|
+
Configuration file:
|
|
104
154
|
|
|
105
155
|
~/.openclaw/.deterministic.json
|
|
106
156
|
|
|
@@ -110,10 +160,6 @@ Example:
|
|
|
110
160
|
"semantic": {
|
|
111
161
|
"HARD_LIMIT": 1200,
|
|
112
162
|
"RISK_THRESHOLD_PERCENT": 85
|
|
113
|
-
},
|
|
114
|
-
"governance": {
|
|
115
|
-
"strict_mode": false,
|
|
116
|
-
"violation_logging": true
|
|
117
163
|
}
|
|
118
164
|
}
|
|
119
165
|
|
|
@@ -140,21 +186,7 @@ Supports:
|
|
|
140
186
|
- Machine-readable JSON output
|
|
141
187
|
- Deterministic backup snapshots
|
|
142
188
|
- Governance event logging
|
|
143
|
-
- CI integration
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## Upgrade Model
|
|
148
|
-
|
|
149
|
-
Templates are version-stamped.
|
|
150
|
-
|
|
151
|
-
Upgrade flow preserves:
|
|
152
|
-
|
|
153
|
-
- Backups
|
|
154
|
-
- Deterministic config
|
|
155
|
-
- User SOUL.md
|
|
156
|
-
|
|
157
|
-
Future releases include safe merge flows for template upgrades.
|
|
189
|
+
- CI integration via exit codes
|
|
158
190
|
|
|
159
191
|
---
|
|
160
192
|
|
|
@@ -181,9 +213,9 @@ Designed for:
|
|
|
181
213
|
- CI-integrated governance
|
|
182
214
|
- Environments requiring auditability
|
|
183
215
|
|
|
184
|
-
If you
|
|
216
|
+
If you want experimentation, use OpenClaw alone.
|
|
185
217
|
|
|
186
|
-
If you
|
|
218
|
+
If you want discipline, use OpenClaw Deterministic.
|
|
187
219
|
|
|
188
220
|
---
|
|
189
221
|
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# OpenClaw Deterministic (OCD) — Roadmap
|
|
2
|
+
|
|
3
|
+
This roadmap outlines the next phases of deterministic governance evolution.
|
|
4
|
+
|
|
5
|
+
The goal is not feature growth.
|
|
6
|
+
|
|
7
|
+
The goal is stronger guarantees.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Governance & Integrity
|
|
12
|
+
|
|
13
|
+
- Safe template merge flow inside upgrade
|
|
14
|
+
- Cooldown state visibility in doctor
|
|
15
|
+
- Semantic shard suggestion automation
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Observability & Automation
|
|
20
|
+
|
|
21
|
+
- Structured logging mode
|
|
22
|
+
- Centralized governance event log (beyond episodic markdown)
|
|
23
|
+
- Compaction activity log
|
|
24
|
+
- Drift detection alerting mode
|
|
25
|
+
|
|
26
|
+
(Status command complete)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Memory System Enhancements
|
|
31
|
+
|
|
32
|
+
- Deterministic shard splitting
|
|
33
|
+
- Automatic semantic pressure warnings
|
|
34
|
+
- Episodic summarization quality check
|
|
35
|
+
- Manual compaction preview mode
|
|
36
|
+
- Token estimation normalization
|
|
37
|
+
- Memory integrity checksum tracking
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Install & Bootstrap
|
|
42
|
+
|
|
43
|
+
- Fresh-install auto-enable refinement
|
|
44
|
+
- Install confirmation summary report
|
|
45
|
+
- Rollback preview mode
|
|
46
|
+
- Backup pruning policy
|
|
47
|
+
- Multi-workspace support
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## CLI Improvements
|
|
52
|
+
|
|
53
|
+
- enable --dry-run
|
|
54
|
+
- revert --preview
|
|
55
|
+
- Help polish
|
|
56
|
+
- Command aliases
|
|
57
|
+
|
|
58
|
+
(Exit codes already formalized via doctor/status)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Architecture & Distribution
|
|
63
|
+
|
|
64
|
+
- Governance flow diagram
|
|
65
|
+
- Memory tier diagram
|
|
66
|
+
- Upgrade policy documentation
|
|
67
|
+
- Integration guide
|
|
68
|
+
- Public positioning statement
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Advanced (Future)
|
|
73
|
+
|
|
74
|
+
- Expanded governance config surface (.deterministic.json)
|
|
75
|
+
- Policy enforcement plugin system
|
|
76
|
+
- Multi-agent compatibility layer
|
|
77
|
+
- External monitoring hook
|
|
78
|
+
- Remote health reporting
|
|
79
|
+
- Immutable governance lock mode
|
|
80
|
+
- Strict mode blocking Tier B auto-execution
|
|
81
|
+
- Deterministic sandbox testing mode
|
package/bin/audit.js
CHANGED
|
@@ -34,6 +34,14 @@ function exists(p) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
function read(p) {
|
|
38
|
+
return fs.readFileSync(p, "utf8");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function stripHeaders(content) {
|
|
42
|
+
return content.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
console.log("\nRunning deterministic audit...\n");
|
|
38
46
|
|
|
39
47
|
let driftFound = false;
|
|
@@ -52,11 +60,27 @@ for (const file of files) {
|
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
try {
|
|
63
|
+
const templateContent = stripHeaders(read(file.template));
|
|
64
|
+
const installedContent = stripHeaders(read(file.installed));
|
|
65
|
+
|
|
66
|
+
// Write stripped content to temp files for diff
|
|
67
|
+
const tmpDir = fs.mkdtempSync(path.join(require("os").tmpdir(), "audit-"));
|
|
68
|
+
const tmpTemplate = path.join(tmpDir, "template");
|
|
69
|
+
const tmpInstalled = path.join(tmpDir, "installed");
|
|
70
|
+
|
|
71
|
+
fs.writeFileSync(tmpTemplate, templateContent);
|
|
72
|
+
fs.writeFileSync(tmpInstalled, installedContent);
|
|
73
|
+
|
|
55
74
|
const diff = execSync(
|
|
56
|
-
`diff -u "${
|
|
75
|
+
`diff -u "${tmpTemplate}" "${tmpInstalled}"`,
|
|
57
76
|
{ stdio: "pipe" }
|
|
58
77
|
).toString();
|
|
59
78
|
|
|
79
|
+
// Cleanup temp files
|
|
80
|
+
fs.unlinkSync(tmpTemplate);
|
|
81
|
+
fs.unlinkSync(tmpInstalled);
|
|
82
|
+
fs.rmdirSync(tmpDir);
|
|
83
|
+
|
|
60
84
|
if (diff.trim().length === 0) {
|
|
61
85
|
console.log(`✅ ${file.name} matches template.`);
|
|
62
86
|
} else {
|
package/bin/upgrade.js
CHANGED
|
@@ -6,6 +6,7 @@ const path = require("path");
|
|
|
6
6
|
|
|
7
7
|
const args = process.argv.slice(2);
|
|
8
8
|
const DRY_RUN = args.includes("--dry-run");
|
|
9
|
+
const FORCE = args.includes("--force");
|
|
9
10
|
|
|
10
11
|
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
11
12
|
const CLI_VERSION = pkg.version;
|
|
@@ -15,6 +16,7 @@ const openclawRoot = path.join(home, ".openclaw");
|
|
|
15
16
|
const workspace = path.join(openclawRoot, "workspace");
|
|
16
17
|
|
|
17
18
|
const VERSION_REGEX = /Installed by openclaw-deterministic v([0-9.]+)/;
|
|
19
|
+
const HASH_REGEX = /Canonical-Hash:\s*SHA256:([a-f0-9]+)/;
|
|
18
20
|
|
|
19
21
|
const files = [
|
|
20
22
|
"OPERATING_RULES.md",
|
|
@@ -48,37 +50,100 @@ function getInstalledVersion(content) {
|
|
|
48
50
|
return match ? match[1] : null;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
|
|
53
|
+
function extractHash(content) {
|
|
54
|
+
const match = content.match(HASH_REGEX);
|
|
55
|
+
return match ? match[1] : null;
|
|
56
|
+
}
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
function stripHeaders(content) {
|
|
59
|
+
return content.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
60
|
+
}
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
const
|
|
62
|
+
function verifyIntegrity(installedContent) {
|
|
63
|
+
const storedHash = extractHash(installedContent);
|
|
64
|
+
if (!storedHash) {
|
|
65
|
+
return { valid: false, reason: "missing-canonical-hash" };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const stripped = stripHeaders(installedContent);
|
|
69
|
+
const crypto = require("crypto");
|
|
70
|
+
const currentHash = crypto
|
|
71
|
+
.createHash("sha256")
|
|
72
|
+
.update(stripped)
|
|
73
|
+
.digest("hex");
|
|
74
|
+
|
|
75
|
+
if (storedHash !== currentHash) {
|
|
76
|
+
return { valid: false, reason: "hash-mismatch" };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { valid: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function loadTemplate(relPath) {
|
|
83
|
+
const templatePath = path.join(__dirname, "..", "templates", relPath);
|
|
84
|
+
if (!exists(templatePath)) {
|
|
85
|
+
console.error(`Template missing: ${relPath}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
return read(templatePath);
|
|
89
|
+
}
|
|
59
90
|
|
|
60
|
-
|
|
91
|
+
function upgradeFile(relPath) {
|
|
92
|
+
const targetPath = path.join(workspace, relPath);
|
|
61
93
|
|
|
62
|
-
if (
|
|
63
|
-
console.log(
|
|
94
|
+
if (!exists(targetPath)) {
|
|
95
|
+
console.log(`⚠ Skipping ${relPath} (not installed).`);
|
|
64
96
|
return;
|
|
65
97
|
}
|
|
66
98
|
|
|
67
|
-
|
|
99
|
+
const installed = read(targetPath);
|
|
100
|
+
const integrity = verifyIntegrity(installed);
|
|
101
|
+
|
|
102
|
+
if (!integrity.valid && !FORCE) {
|
|
103
|
+
console.error(
|
|
104
|
+
`❌ Refusing to upgrade ${relPath}: ${integrity.reason}.`
|
|
105
|
+
);
|
|
106
|
+
console.error(
|
|
107
|
+
" File has been modified or is missing canonical header."
|
|
108
|
+
);
|
|
109
|
+
console.error(" Re-run with --force to override.");
|
|
110
|
+
process.exit(2);
|
|
111
|
+
}
|
|
68
112
|
|
|
69
|
-
const
|
|
113
|
+
const template = loadTemplate(relPath);
|
|
114
|
+
|
|
115
|
+
const stamped = template.replace(
|
|
116
|
+
VERSION_REGEX,
|
|
117
|
+
`Installed by openclaw-deterministic v${CLI_VERSION}`
|
|
118
|
+
);
|
|
70
119
|
|
|
71
120
|
write(targetPath, stamped);
|
|
121
|
+
|
|
122
|
+
if (!DRY_RUN) {
|
|
123
|
+
console.log(`✅ Upgraded ${relPath} → v${CLI_VERSION}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!exists(openclawRoot)) {
|
|
128
|
+
console.error("OpenClaw not found at ~/.openclaw");
|
|
129
|
+
process.exit(1);
|
|
72
130
|
}
|
|
73
131
|
|
|
74
|
-
if (!exists(
|
|
75
|
-
console.error("OpenClaw workspace
|
|
132
|
+
if (!exists(workspace)) {
|
|
133
|
+
console.error("OpenClaw workspace missing at ~/.openclaw/workspace");
|
|
76
134
|
process.exit(1);
|
|
77
135
|
}
|
|
78
136
|
|
|
79
|
-
console.log(
|
|
137
|
+
console.log(`\nRunning deterministic upgrade → v${CLI_VERSION}\n`);
|
|
80
138
|
|
|
81
|
-
files
|
|
139
|
+
for (const rel of files) {
|
|
140
|
+
upgradeFile(rel);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (DRY_RUN) {
|
|
144
|
+
console.log("\nDry-run complete. No changes written.\n");
|
|
145
|
+
} else {
|
|
146
|
+
console.log("\nUpgrade complete.\n");
|
|
147
|
+
}
|
|
82
148
|
|
|
83
|
-
console.log("\nUpgrade complete.\n");
|
|
84
149
|
process.exit(0);
|