@det-acp/core 0.2.0
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 +21 -0
- package/README.md +492 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +308 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +32 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +234 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/templates.d.ts +27 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +266 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/engine/action-registry.d.ts +49 -0
- package/dist/engine/action-registry.d.ts.map +1 -0
- package/dist/engine/action-registry.js +95 -0
- package/dist/engine/action-registry.js.map +1 -0
- package/dist/engine/gate.d.ts +57 -0
- package/dist/engine/gate.d.ts.map +1 -0
- package/dist/engine/gate.js +145 -0
- package/dist/engine/gate.js.map +1 -0
- package/dist/engine/runtime.d.ts +98 -0
- package/dist/engine/runtime.d.ts.map +1 -0
- package/dist/engine/runtime.js +138 -0
- package/dist/engine/runtime.js.map +1 -0
- package/dist/engine/session.d.ts +74 -0
- package/dist/engine/session.d.ts.map +1 -0
- package/dist/engine/session.js +343 -0
- package/dist/engine/session.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/ledger.d.ts +58 -0
- package/dist/ledger/ledger.d.ts.map +1 -0
- package/dist/ledger/ledger.js +188 -0
- package/dist/ledger/ledger.js.map +1 -0
- package/dist/ledger/query.d.ts +29 -0
- package/dist/ledger/query.d.ts.map +1 -0
- package/dist/ledger/query.js +61 -0
- package/dist/ledger/query.js.map +1 -0
- package/dist/ledger/types.d.ts +27 -0
- package/dist/ledger/types.d.ts.map +1 -0
- package/dist/ledger/types.js +5 -0
- package/dist/ledger/types.js.map +1 -0
- package/dist/policy/evaluator.d.ts +21 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +383 -0
- package/dist/policy/evaluator.js.map +1 -0
- package/dist/policy/loader.d.ts +27 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +69 -0
- package/dist/policy/loader.js.map +1 -0
- package/dist/policy/schema.d.ts +168 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +107 -0
- package/dist/policy/schema.js.map +1 -0
- package/dist/proxy/mcp-proxy.d.ts +43 -0
- package/dist/proxy/mcp-proxy.d.ts.map +1 -0
- package/dist/proxy/mcp-proxy.js +240 -0
- package/dist/proxy/mcp-proxy.js.map +1 -0
- package/dist/proxy/mcp-types.d.ts +79 -0
- package/dist/proxy/mcp-types.d.ts.map +1 -0
- package/dist/proxy/mcp-types.js +28 -0
- package/dist/proxy/mcp-types.js.map +1 -0
- package/dist/proxy/shell-proxy.d.ts +52 -0
- package/dist/proxy/shell-proxy.d.ts.map +1 -0
- package/dist/proxy/shell-proxy.js +92 -0
- package/dist/proxy/shell-proxy.js.map +1 -0
- package/dist/rollback/manager.d.ts +62 -0
- package/dist/rollback/manager.d.ts.map +1 -0
- package/dist/rollback/manager.js +151 -0
- package/dist/rollback/manager.js.map +1 -0
- package/dist/server/server.d.ts +24 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +200 -0
- package/dist/server/server.js.map +1 -0
- package/dist/tools/base.d.ts +58 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +48 -0
- package/dist/tools/base.js.map +1 -0
- package/dist/tools/command-run.d.ts +30 -0
- package/dist/tools/command-run.d.ts.map +1 -0
- package/dist/tools/command-run.js +87 -0
- package/dist/tools/command-run.js.map +1 -0
- package/dist/tools/file-read.d.ts +34 -0
- package/dist/tools/file-read.d.ts.map +1 -0
- package/dist/tools/file-read.js +67 -0
- package/dist/tools/file-read.js.map +1 -0
- package/dist/tools/file-write.d.ts +39 -0
- package/dist/tools/file-write.d.ts.map +1 -0
- package/dist/tools/file-write.js +158 -0
- package/dist/tools/file-write.js.map +1 -0
- package/dist/tools/git.d.ts +48 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +193 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/http-request.d.ts +48 -0
- package/dist/tools/http-request.d.ts.map +1 -0
- package/dist/tools/http-request.js +91 -0
- package/dist/tools/http-request.js.map +1 -0
- package/dist/types.d.ts +257 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/examples/coding-agent.policy.yaml +80 -0
- package/examples/devops-deploy.policy.yaml +107 -0
- package/examples/mcp-proxy.config.yaml +34 -0
- package/examples/simple-session.ts +161 -0
- package/examples/video-upscaler.policy.yaml +86 -0
- package/package.json +92 -0
- package/schemas/generate.ts +18 -0
- package/schemas/policy.schema.json +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 det-acp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
# Deterministic Agent Control Protocol
|
|
2
|
+
|
|
3
|
+
A governance gateway for AI agents — makes any agent bounded, auditable, reversible, and explainable.
|
|
4
|
+
|
|
5
|
+
Works transparently with **Cursor**, **Claude Code**, **Codex**, and any MCP-compatible agent via the MCP proxy. Also supports shell command governance and a language-agnostic HTTP API.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Instead of agents executing tools directly, every action flows through the control plane:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Agent → Control Protocol (evaluate) → allow / deny / gate
|
|
13
|
+
↓ (if allowed)
|
|
14
|
+
Agent executes action
|
|
15
|
+
↓
|
|
16
|
+
Control Protocol (record result)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The control protocol **does not execute** actions — it evaluates them against a policy, enforces session-level budgets, requires human approval for risky actions, and records everything in a tamper-evident audit ledger.
|
|
20
|
+
|
|
21
|
+
## Core Principles
|
|
22
|
+
|
|
23
|
+
- **Bounded**: Agents can only perform allowed actions in allowed scopes
|
|
24
|
+
- **Session-Aware**: Budget, rate limits, and escalation rules across the full interaction
|
|
25
|
+
- **Auditable**: Every action logged in a tamper-evident ledger with SHA-256 hash chaining
|
|
26
|
+
- **Reversible**: Compensation plans for undoing executed actions
|
|
27
|
+
- **Explainable**: Full reporting — what was allowed, denied, gated, and why
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install deterministic-agent-control-protocol
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Set Up Governance (One Command)
|
|
38
|
+
|
|
39
|
+
The fastest way to add governance to your AI agent:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Cursor
|
|
43
|
+
npx det-acp init cursor
|
|
44
|
+
|
|
45
|
+
# Codex CLI
|
|
46
|
+
npx det-acp init codex
|
|
47
|
+
|
|
48
|
+
# Claude Code
|
|
49
|
+
npx det-acp init claude-code
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This generates all required files (policy, MCP config, governance rules) with sensible defaults. The only file you may want to edit is `policy.yaml` — everything else is handled automatically.
|
|
53
|
+
|
|
54
|
+
To use your own policy instead of the default:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx det-acp init cursor --policy ./my-policy.yaml
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
After running `init`, restart your agent (Cursor, Claude Code, etc.) to pick up the MCP server.
|
|
61
|
+
|
|
62
|
+
### Define a Policy
|
|
63
|
+
|
|
64
|
+
Create an `agent.policy.yaml`:
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
version: "1.0"
|
|
68
|
+
name: "my-agent"
|
|
69
|
+
|
|
70
|
+
capabilities:
|
|
71
|
+
- tool: "file:read"
|
|
72
|
+
scope:
|
|
73
|
+
paths: ["./src/**"]
|
|
74
|
+
- tool: "file:write"
|
|
75
|
+
scope:
|
|
76
|
+
paths: ["./src/**"]
|
|
77
|
+
- tool: "command:run"
|
|
78
|
+
scope:
|
|
79
|
+
binaries: ["npm", "node", "tsc"]
|
|
80
|
+
|
|
81
|
+
limits:
|
|
82
|
+
max_runtime_ms: 1800000
|
|
83
|
+
max_files_changed: 50
|
|
84
|
+
|
|
85
|
+
gates:
|
|
86
|
+
- action: "file:delete"
|
|
87
|
+
approval: "human"
|
|
88
|
+
risk_level: "high"
|
|
89
|
+
|
|
90
|
+
evidence:
|
|
91
|
+
require: ["checksums", "diffs"]
|
|
92
|
+
format: "jsonl"
|
|
93
|
+
|
|
94
|
+
forbidden:
|
|
95
|
+
- pattern: "**/.env"
|
|
96
|
+
- pattern: "rm -rf"
|
|
97
|
+
|
|
98
|
+
session:
|
|
99
|
+
max_actions: 100
|
|
100
|
+
max_denials: 10
|
|
101
|
+
rate_limit:
|
|
102
|
+
max_per_minute: 30
|
|
103
|
+
escalation:
|
|
104
|
+
- after_actions: 50
|
|
105
|
+
require: human_checkin
|
|
106
|
+
- after_minutes: 15
|
|
107
|
+
require: human_checkin
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Use as a Library
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { AgentGateway } from 'deterministic-agent-control-protocol';
|
|
114
|
+
|
|
115
|
+
const gateway = await AgentGateway.create({
|
|
116
|
+
ledgerDir: './ledgers',
|
|
117
|
+
onStateChange: (sessionId, from, to) => console.log(`${from} -> ${to}`),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Create a session
|
|
121
|
+
const session = await gateway.createSession('./agent.policy.yaml', {
|
|
122
|
+
agent: 'my-coding-agent',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Evaluate an action (does NOT execute it)
|
|
126
|
+
const verdict = await gateway.evaluate(session.id, {
|
|
127
|
+
tool: 'file:read',
|
|
128
|
+
input: { path: './src/index.ts' },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (verdict.decision === 'allow') {
|
|
132
|
+
// Execute the action yourself (or via your agent)
|
|
133
|
+
const content = fs.readFileSync('./src/index.ts', 'utf-8');
|
|
134
|
+
|
|
135
|
+
// Record the result
|
|
136
|
+
await gateway.recordResult(session.id, verdict.actionId, {
|
|
137
|
+
success: true,
|
|
138
|
+
output: content,
|
|
139
|
+
durationMs: 5,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// When done, terminate and get report
|
|
144
|
+
const report = await gateway.terminateSession(session.id, 'task complete');
|
|
145
|
+
console.log(`Allowed: ${report.allowed}, Denied: ${report.denied}`);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Agent Integrations
|
|
151
|
+
|
|
152
|
+
Ready-to-use integration guides for popular AI agents. Each integration includes a policy, config templates, governance rules, test sandbox, and step-by-step instructions.
|
|
153
|
+
|
|
154
|
+
| Agent | Integration Mode | Governance Level | Guide |
|
|
155
|
+
| --------------------- | ------------------------------------- | ---------------- | --------------------------------------------------- |
|
|
156
|
+
| **Cursor** | MCP Proxy + Cursor Rules | Soft | [integrations/cursor/](integrations/cursor/) |
|
|
157
|
+
| **Codex CLI** | MCP Proxy + AGENTS.md + OS Sandbox | Soft + Sandbox | [integrations/codex/](integrations/codex/) |
|
|
158
|
+
| **Claude Code** | MCP Proxy + CLAUDE.md + settings.json | Soft + Semi-Hard | [integrations/claude-code/](integrations/claude-code/) |
|
|
159
|
+
| **OpenClaw** | HTTP API + Skill + Docker Sandbox | Hard | [integrations/openclaw/](integrations/openclaw/) |
|
|
160
|
+
|
|
161
|
+
### Governance Levels Explained
|
|
162
|
+
|
|
163
|
+
- **Soft**: The LLM is instructed (via rules/instructions files) to prefer governed tools. Effective in practice, but a creative prompt could theoretically bypass it.
|
|
164
|
+
- **Semi-Hard**: Soft instructions combined with the agent's built-in permission system that can deny direct tool access (e.g., Claude Code's `settings.json`).
|
|
165
|
+
- **Hard**: The agent physically cannot access tools outside the governance layer. Achieved via Docker sandboxing, tool allow/deny lists, or custom agent harnesses.
|
|
166
|
+
|
|
167
|
+
For any MCP-compatible agent not listed above, see the general MCP Proxy setup below.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Other Integration Modes
|
|
172
|
+
|
|
173
|
+
### MCP Proxy (General)
|
|
174
|
+
|
|
175
|
+
The MCP proxy works with any MCP-compatible client, not just Cursor.
|
|
176
|
+
|
|
177
|
+
**Simplified mode** — just point it at a policy file and it auto-configures a filesystem backend:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npx det-acp proxy --policy ./policy.yaml
|
|
181
|
+
npx det-acp proxy --policy ./policy.yaml --dir /path/to/project # custom project dir
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Full config mode** — for advanced setups with multiple backends, SSE transport, etc.:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Create a proxy config
|
|
188
|
+
cat > mcp-proxy.config.yaml << 'EOF'
|
|
189
|
+
policy: ./agent.policy.yaml
|
|
190
|
+
ledger_dir: ./.det-acp/ledgers
|
|
191
|
+
transport: stdio
|
|
192
|
+
backends:
|
|
193
|
+
- name: filesystem
|
|
194
|
+
transport: stdio
|
|
195
|
+
command: npx
|
|
196
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "./src"]
|
|
197
|
+
EOF
|
|
198
|
+
|
|
199
|
+
# Start the proxy
|
|
200
|
+
npx det-acp proxy ./mcp-proxy.config.yaml
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Shell Proxy
|
|
204
|
+
|
|
205
|
+
Execute commands through the policy gateway:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Allowed
|
|
209
|
+
npx det-acp exec ./agent.policy.yaml echo "hello"
|
|
210
|
+
|
|
211
|
+
# Denied (rm -rf is forbidden)
|
|
212
|
+
npx det-acp exec ./agent.policy.yaml rm -rf /tmp
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### HTTP Session Server
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Start the server
|
|
219
|
+
npx det-acp serve --port 3100
|
|
220
|
+
|
|
221
|
+
# Create a session
|
|
222
|
+
curl -X POST http://localhost:3100/sessions \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{"policy": "version: \"1.0\"\nname: test\ncapabilities:\n - tool: file:read\n scope:\n paths: [\"./src/**\"]"}'
|
|
225
|
+
|
|
226
|
+
# Evaluate an action
|
|
227
|
+
curl -X POST http://localhost:3100/sessions/<session-id>/evaluate \
|
|
228
|
+
-H "Content-Type: application/json" \
|
|
229
|
+
-d '{"action": {"tool": "file:read", "input": {"path": "./src/index.ts"}}}'
|
|
230
|
+
|
|
231
|
+
# Record result
|
|
232
|
+
curl -X POST http://localhost:3100/sessions/<session-id>/record \
|
|
233
|
+
-H "Content-Type: application/json" \
|
|
234
|
+
-d '{"actionId": "<action-id>", "result": {"success": true, "output": "..."}}'
|
|
235
|
+
|
|
236
|
+
# Terminate session
|
|
237
|
+
curl -X POST http://localhost:3100/sessions/<session-id>/terminate
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### CLI
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Set up governance for an integration (generates all config files)
|
|
244
|
+
npx det-acp init cursor # or codex, claude-code
|
|
245
|
+
npx det-acp init cursor --policy ./my-policy.yaml # use custom policy
|
|
246
|
+
|
|
247
|
+
# Validate a policy
|
|
248
|
+
npx det-acp validate ./agent.policy.yaml
|
|
249
|
+
|
|
250
|
+
# Start MCP proxy (simplified — just a policy file)
|
|
251
|
+
npx det-acp proxy --policy ./policy.yaml
|
|
252
|
+
|
|
253
|
+
# Start MCP proxy (full config file for advanced use)
|
|
254
|
+
npx det-acp proxy ./mcp-proxy.config.yaml
|
|
255
|
+
|
|
256
|
+
# Execute a command through shell proxy
|
|
257
|
+
npx det-acp exec ./agent.policy.yaml echo "hello"
|
|
258
|
+
|
|
259
|
+
# View audit report from ledger
|
|
260
|
+
npx det-acp report ./.det-acp/ledgers/<session-id>.jsonl
|
|
261
|
+
|
|
262
|
+
# Start HTTP session server
|
|
263
|
+
npx det-acp serve
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Architecture
|
|
267
|
+
|
|
268
|
+
### Component Architecture
|
|
269
|
+
|
|
270
|
+
```mermaid
|
|
271
|
+
graph TB
|
|
272
|
+
subgraph ExternalSystems [External Systems]
|
|
273
|
+
BackendMCP["Backend MCP Servers"]
|
|
274
|
+
HumanApprover["Human / Webhook Approvers"]
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
subgraph IntegrationLayer [Integration Layer]
|
|
278
|
+
MCPProxy["MCPProxyServer"]
|
|
279
|
+
ShellProxyNode["ShellProxy"]
|
|
280
|
+
HTTPServer["HTTP Server - Fastify"]
|
|
281
|
+
LibrarySDK["Library SDK - TypeScript"]
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
subgraph CoreEngine [Core Engine]
|
|
285
|
+
Gateway["AgentGateway"]
|
|
286
|
+
SessionMgr["SessionManager"]
|
|
287
|
+
PolicyEval["PolicyEvaluator"]
|
|
288
|
+
GateMgr["GateManager"]
|
|
289
|
+
Registry["ActionRegistry"]
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
subgraph InfraLayer [Infrastructure]
|
|
293
|
+
Ledger["EvidenceLedger - JSONL + SHA-256 Hash Chain"]
|
|
294
|
+
Rollback["RollbackManager"]
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
subgraph ToolAdapters [Tool Adapters]
|
|
298
|
+
FileRead["file:read"]
|
|
299
|
+
FileWrite["file:write"]
|
|
300
|
+
CommandRun["command:run"]
|
|
301
|
+
HttpReq["http:request"]
|
|
302
|
+
GitDiff["git:diff"]
|
|
303
|
+
GitApply["git:apply"]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
MCPProxy --> Gateway
|
|
307
|
+
ShellProxyNode --> Gateway
|
|
308
|
+
HTTPServer --> Gateway
|
|
309
|
+
LibrarySDK --> Gateway
|
|
310
|
+
|
|
311
|
+
Gateway --> SessionMgr
|
|
312
|
+
Gateway --> Registry
|
|
313
|
+
Gateway --> GateMgr
|
|
314
|
+
|
|
315
|
+
SessionMgr --> PolicyEval
|
|
316
|
+
SessionMgr --> GateMgr
|
|
317
|
+
SessionMgr --> Ledger
|
|
318
|
+
|
|
319
|
+
Registry --> FileRead
|
|
320
|
+
Registry --> FileWrite
|
|
321
|
+
Registry --> CommandRun
|
|
322
|
+
Registry --> HttpReq
|
|
323
|
+
Registry --> GitDiff
|
|
324
|
+
Registry --> GitApply
|
|
325
|
+
|
|
326
|
+
Rollback --> Registry
|
|
327
|
+
Rollback --> Ledger
|
|
328
|
+
|
|
329
|
+
MCPProxy --> BackendMCP
|
|
330
|
+
GateMgr --> HumanApprover
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Action Evaluation Flow
|
|
334
|
+
|
|
335
|
+
```mermaid
|
|
336
|
+
sequenceDiagram
|
|
337
|
+
participant Agent
|
|
338
|
+
participant Integration as Integration Layer
|
|
339
|
+
participant Gateway as AgentGateway
|
|
340
|
+
participant Session as SessionManager
|
|
341
|
+
participant Policy as PolicyEvaluator
|
|
342
|
+
participant Gate as GateManager
|
|
343
|
+
participant Ledger as EvidenceLedger
|
|
344
|
+
|
|
345
|
+
Agent->>Integration: Action request (tool, input)
|
|
346
|
+
Integration->>Gateway: evaluate(sessionId, action)
|
|
347
|
+
Gateway->>Session: evaluate(sessionId, action)
|
|
348
|
+
|
|
349
|
+
Session->>Policy: evaluateSessionAction(action, policy, session)
|
|
350
|
+
Note right of Policy: 1. Session state check<br/>2. Session constraints<br/>(max_actions, rate_limit, escalation)<br/>3. Forbidden patterns<br/>4. Capability + scope<br/>5. Budget limits<br/>6. Gate lookup
|
|
351
|
+
Policy-->>Session: ValidationResult (allow / deny / gate)
|
|
352
|
+
|
|
353
|
+
Session->>Ledger: append("action:evaluate", ...)
|
|
354
|
+
|
|
355
|
+
alt Verdict is gate
|
|
356
|
+
Session->>Gate: requestApproval(sessionId, actionId, action, gate)
|
|
357
|
+
alt Auto or handler resolves
|
|
358
|
+
Gate-->>Session: approved / rejected
|
|
359
|
+
else Human approval pending
|
|
360
|
+
Gate-->>Session: pending
|
|
361
|
+
Note over Agent,Gate: Session paused until gate resolved
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
Session-->>Gateway: EvaluateResponse
|
|
366
|
+
Gateway-->>Integration: decision + reasons
|
|
367
|
+
Integration-->>Agent: allow / deny / gate
|
|
368
|
+
|
|
369
|
+
alt Decision is allow
|
|
370
|
+
Note over Agent: Agent executes action externally
|
|
371
|
+
Agent->>Integration: recordResult(actionId, result)
|
|
372
|
+
Integration->>Gateway: recordResult(sessionId, actionId, result)
|
|
373
|
+
Gateway->>Session: recordResult(sessionId, actionId, result)
|
|
374
|
+
Session->>Session: Update budget (filesChanged, outputBytes)
|
|
375
|
+
Session->>Ledger: append("action:result", ...)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
opt Session complete
|
|
379
|
+
Agent->>Integration: terminateSession()
|
|
380
|
+
Integration->>Gateway: terminateSession(sessionId)
|
|
381
|
+
Gateway->>Session: terminate(sessionId)
|
|
382
|
+
Session->>Ledger: append("session:terminate", ...)
|
|
383
|
+
Session-->>Gateway: SessionReport
|
|
384
|
+
Gateway-->>Integration: SessionReport
|
|
385
|
+
Integration-->>Agent: SessionReport
|
|
386
|
+
end
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Session Lifecycle
|
|
390
|
+
|
|
391
|
+
Every interaction is governed through a session:
|
|
392
|
+
|
|
393
|
+
```
|
|
394
|
+
Create Session → Evaluate Actions → Record Results → Terminate
|
|
395
|
+
↕ (repeat) ↕ (repeat)
|
|
396
|
+
deny / gate
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Sessions track:
|
|
400
|
+
|
|
401
|
+
- Cumulative budget (runtime, files changed, cost)
|
|
402
|
+
- Action history (for rate limiting and escalation)
|
|
403
|
+
- Pending gates (human approval required)
|
|
404
|
+
- Evidence ledger (tamper-evident audit trail)
|
|
405
|
+
|
|
406
|
+
### Integration Modes
|
|
407
|
+
|
|
408
|
+
| Mode | How it works | Best for |
|
|
409
|
+
| --------------------- | ----------------------------------------------- | ----------------------------------- |
|
|
410
|
+
| **MCP Proxy** | Transparent proxy between agent and MCP servers | Cursor, Claude Code, any MCP client |
|
|
411
|
+
| **Shell Proxy** | Command wrapper that validates before executing | CLI agents, shell-based workflows |
|
|
412
|
+
| **HTTP API** | REST endpoints for session management | Any language, custom integrations |
|
|
413
|
+
| **Library SDK** | TypeScript API for in-process governance | Custom TypeScript agents |
|
|
414
|
+
|
|
415
|
+
### Evidence Ledger
|
|
416
|
+
|
|
417
|
+
Every action produces an immutable audit record in JSONL format with SHA-256 hash chaining:
|
|
418
|
+
|
|
419
|
+
```jsonl
|
|
420
|
+
{"seq":1,"ts":"...","hash":"sha256:abc...","prev":"sha256:000...","type":"session:start","data":{...}}
|
|
421
|
+
{"seq":2,"ts":"...","hash":"sha256:def...","prev":"sha256:abc...","type":"action:evaluate","data":{...}}
|
|
422
|
+
{"seq":3,"ts":"...","hash":"sha256:ghi...","prev":"sha256:def...","type":"action:result","data":{...}}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
If any entry is tampered with, the hash chain breaks and integrity verification fails.
|
|
426
|
+
|
|
427
|
+
### Policy DSL
|
|
428
|
+
|
|
429
|
+
Policies define:
|
|
430
|
+
|
|
431
|
+
| Section | Purpose |
|
|
432
|
+
| ---------------- | ---------------------------------------------------------------- |
|
|
433
|
+
| `capabilities` | What tools the agent can use and where |
|
|
434
|
+
| `limits` | Runtime, cost, file change, and retry budgets |
|
|
435
|
+
| `gates` | Actions that require human/webhook approval |
|
|
436
|
+
| `evidence` | What artifacts must be recorded |
|
|
437
|
+
| `forbidden` | Patterns that are always blocked |
|
|
438
|
+
| `session` | Session-level constraints (max actions, rate limits, escalation) |
|
|
439
|
+
| `remediation` | Error handling rules and fallback chains |
|
|
440
|
+
|
|
441
|
+
### Built-in Tool Adapters
|
|
442
|
+
|
|
443
|
+
| Tool | Description |
|
|
444
|
+
| ---------------- | ------------------------------------------- |
|
|
445
|
+
| `file:read` | Read files within scoped paths |
|
|
446
|
+
| `file:write` | Write files with backup for rollback |
|
|
447
|
+
| `command:run` | Execute allow-listed binaries with timeout |
|
|
448
|
+
| `http:request` | HTTP requests to allow-listed domains |
|
|
449
|
+
| `git:diff` | Get git diff output |
|
|
450
|
+
| `git:apply` | Apply git patches with stash-based rollback |
|
|
451
|
+
|
|
452
|
+
### Custom Tool Adapters
|
|
453
|
+
|
|
454
|
+
Extend the `ToolAdapter` base class:
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
import { ToolAdapter } from 'deterministic-agent-control-protocol';
|
|
458
|
+
|
|
459
|
+
class MyCustomTool extends ToolAdapter {
|
|
460
|
+
name = 'custom:mytool';
|
|
461
|
+
description = 'My custom tool';
|
|
462
|
+
inputSchema = z.object({ /* ... */ });
|
|
463
|
+
|
|
464
|
+
validate(input, policy) { /* ... */ }
|
|
465
|
+
async dryRun(input, ctx) { /* ... */ }
|
|
466
|
+
async execute(input, ctx) { /* ... */ }
|
|
467
|
+
async rollback(input, ctx) { /* ... */ }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Register it
|
|
471
|
+
gateway.getRegistry().register(new MyCustomTool());
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Development
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
# Install dependencies
|
|
478
|
+
npm install
|
|
479
|
+
|
|
480
|
+
# Type check
|
|
481
|
+
npm run lint
|
|
482
|
+
|
|
483
|
+
# Run tests
|
|
484
|
+
npm test
|
|
485
|
+
|
|
486
|
+
# Build
|
|
487
|
+
npm run build
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## License
|
|
491
|
+
|
|
492
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic Agent Control Protocol CLI
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* init <integration> Set up governance for cursor, codex, or claude-code
|
|
7
|
+
* validate <policy.yaml> Validate a policy file
|
|
8
|
+
* serve Start the HTTP session server
|
|
9
|
+
* proxy [config.yaml] Start the MCP proxy server
|
|
10
|
+
* proxy --policy <policy.yaml> Start MCP proxy with auto-configured defaults
|
|
11
|
+
* exec <policy.yaml> -- <command> Execute a command through the shell proxy
|
|
12
|
+
* report <ledger-file> Show ledger summary
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG"}
|