@decionis/agent-safe-pipeline 0.1.3 → 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/README.md +477 -16
- package/dist/Index.d.ts +9 -0
- package/dist/Index.d.ts.map +1 -1
- package/dist/Index.js +8 -0
- package/dist/Index.js.map +1 -1
- package/dist/approval/PresenceApprovalCoordinator.d.ts +25 -0
- package/dist/approval/PresenceApprovalCoordinator.d.ts.map +1 -1
- package/dist/approval/PresenceApprovalCoordinator.js +54 -6
- package/dist/approval/PresenceApprovalCoordinator.js.map +1 -1
- package/dist/audit/AuditRecorder.d.ts +122 -0
- package/dist/audit/AuditRecorder.d.ts.map +1 -0
- package/dist/audit/AuditRecorder.js +312 -0
- package/dist/audit/AuditRecorder.js.map +1 -0
- package/dist/decision/CreateGate.d.ts +123 -0
- package/dist/decision/CreateGate.d.ts.map +1 -0
- package/dist/decision/CreateGate.js +211 -0
- package/dist/decision/CreateGate.js.map +1 -0
- package/dist/decision/DecionisGate.d.ts +109 -3
- package/dist/decision/DecionisGate.d.ts.map +1 -1
- package/dist/decision/DecionisGate.js +823 -46
- package/dist/decision/DecionisGate.js.map +1 -1
- package/dist/decision/DecisionAuthority.d.ts +76 -1
- package/dist/decision/DecisionAuthority.d.ts.map +1 -1
- package/dist/decision/DecisionAuthority.js.map +1 -1
- package/dist/decision/FixtureDecisionAuthority.d.ts +27 -1
- package/dist/decision/FixtureDecisionAuthority.d.ts.map +1 -1
- package/dist/decision/FixtureDecisionAuthority.js +47 -0
- package/dist/decision/FixtureDecisionAuthority.js.map +1 -1
- package/dist/decision/ImmutableGateDecision.d.ts.map +1 -1
- package/dist/decision/ImmutableGateDecision.js +26 -0
- package/dist/decision/ImmutableGateDecision.js.map +1 -1
- package/dist/decision/Provision.d.ts +33 -0
- package/dist/decision/Provision.d.ts.map +1 -0
- package/dist/decision/Provision.js +116 -0
- package/dist/decision/Provision.js.map +1 -0
- package/dist/decision/ShadowGate.d.ts +31 -0
- package/dist/decision/ShadowGate.d.ts.map +1 -0
- package/dist/decision/ShadowGate.js +79 -0
- package/dist/decision/ShadowGate.js.map +1 -0
- package/dist/execution/ActionRegistry.d.ts +66 -0
- package/dist/execution/ActionRegistry.d.ts.map +1 -1
- package/dist/execution/ActionRegistry.js +110 -1
- package/dist/execution/ActionRegistry.js.map +1 -1
- package/dist/execution/AuthorizationVerifier.d.ts +149 -1
- package/dist/execution/AuthorizationVerifier.d.ts.map +1 -1
- package/dist/execution/AuthorizationVerifier.js +302 -27
- package/dist/execution/AuthorizationVerifier.js.map +1 -1
- package/dist/execution/SafeExecutor.d.ts +102 -7
- package/dist/execution/SafeExecutor.d.ts.map +1 -1
- package/dist/execution/SafeExecutor.js +288 -17
- package/dist/execution/SafeExecutor.js.map +1 -1
- package/dist/http/ClientIdentification.d.ts +22 -0
- package/dist/http/ClientIdentification.d.ts.map +1 -0
- package/dist/http/ClientIdentification.js +44 -0
- package/dist/http/ClientIdentification.js.map +1 -0
- package/dist/http/Credential.d.ts +17 -0
- package/dist/http/Credential.d.ts.map +1 -0
- package/dist/http/Credential.js +5 -0
- package/dist/http/Credential.js.map +1 -0
- package/dist/http/StoredCredentials.d.ts +34 -0
- package/dist/http/StoredCredentials.d.ts.map +1 -0
- package/dist/http/StoredCredentials.js +85 -0
- package/dist/http/StoredCredentials.js.map +1 -0
- package/dist/intent/CanonicalIntentHasher.d.ts +1 -1
- package/dist/intent/CanonicalIntentHasher.d.ts.map +1 -1
- package/dist/intent/CanonicalIntentHasher.js +9 -2
- package/dist/intent/CanonicalIntentHasher.js.map +1 -1
- package/dist/intent/ExecutionIntent.d.ts +26 -2
- package/dist/intent/ExecutionIntent.d.ts.map +1 -1
- package/dist/intent/ExecutionIntent.js +11 -0
- package/dist/intent/ExecutionIntent.js.map +1 -1
- package/dist/intent/IntentCapture.d.ts +5 -0
- package/dist/intent/IntentCapture.d.ts.map +1 -1
- package/dist/intent/IntentCapture.js +15 -1
- package/dist/intent/IntentCapture.js.map +1 -1
- package/dist/report/DecisionReport.d.ts +22 -0
- package/dist/report/DecisionReport.d.ts.map +1 -0
- package/dist/report/DecisionReport.js +37 -0
- package/dist/report/DecisionReport.js.map +1 -0
- package/dist/report/DossierReport.d.ts +43 -0
- package/dist/report/DossierReport.d.ts.map +1 -0
- package/dist/report/DossierReport.js +130 -0
- package/dist/report/DossierReport.js.map +1 -0
- package/dist/report/HostedOutcome.d.ts +18 -0
- package/dist/report/HostedOutcome.d.ts.map +1 -0
- package/dist/report/HostedOutcome.js +24 -0
- package/dist/report/HostedOutcome.js.map +1 -0
- package/dist/shadow/ShadowPipeline.d.ts +75 -5
- package/dist/shadow/ShadowPipeline.d.ts.map +1 -1
- package/dist/shadow/ShadowPipeline.js +157 -7
- package/dist/shadow/ShadowPipeline.js.map +1 -1
- package/dist/testing/Index.d.ts +12 -0
- package/dist/testing/Index.d.ts.map +1 -0
- package/dist/testing/Index.js +12 -0
- package/dist/testing/Index.js.map +1 -0
- package/dist/testing/LocalAuthority.d.ts +292 -0
- package/dist/testing/LocalAuthority.d.ts.map +1 -0
- package/dist/testing/LocalAuthority.js +1124 -0
- package/dist/testing/LocalAuthority.js.map +1 -0
- package/dist/testing/LocalPresence.d.ts +210 -0
- package/dist/testing/LocalPresence.d.ts.map +1 -0
- package/dist/testing/LocalPresence.js +473 -0
- package/dist/testing/LocalPresence.js.map +1 -0
- package/package.json +40 -4
package/README.md
CHANGED
|
@@ -1,28 +1,95 @@
|
|
|
1
1
|
# `@decionis/agent-safe-pipeline`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@decionis/agent-safe-pipeline)
|
|
4
|
+
[](https://github.com/decionis/agent-safe-pipeline/actions/workflows/deploy.yml)
|
|
5
|
+
[](https://scorecard.dev/viewer/?uri=github.com/decionis/agent-safe-pipeline)
|
|
6
|
+
[](https://www.bestpractices.dev/projects/14098)
|
|
7
|
+
[](https://github.com/decionis/agent-safe-pipeline/blob/master/LICENSE)
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
**Let agents propose. Let policy decide.**
|
|
10
|
+
|
|
11
|
+
`@decionis/agent-safe-pipeline` is the TypeScript reference implementation of the Execution
|
|
12
|
+
Authority architecture. An AI agent may reason, plan, and propose a consequential action. It cannot
|
|
13
|
+
authorize that action, hold the credentials that perform it, or choose which trusted code runs. The
|
|
14
|
+
exact proposal is captured as an immutable, short-lived intent, evaluated independently by Decionis,
|
|
15
|
+
escalated to a verified human when policy requires it, and executed only through a single-use grant
|
|
16
|
+
bound to that one intent. Every decision leaves a Decision Dossier, so the record of what was
|
|
17
|
+
authorized, under which policy, and on whose approval compounds over time.
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
Agent -> immutable intent -> Decionis -> ALLOW / ESCALATE / BLOCK -> SafeExecutor -> downstream API
|
|
21
|
+
|
|
|
22
|
+
+-> Presence -> verified human approval -> Decionis re-evaluation
|
|
23
|
+
|
|
|
24
|
+
+-> Decision Dossier -> compounding decision record
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The package is a library, not a hosted service. It supplies the boundary; Decionis supplies the
|
|
28
|
+
decision. Its safety claims hold only when the documented trust boundary is preserved: the agent
|
|
29
|
+
runtime never sees Decionis credentials, downstream credentials, or the handler registry.
|
|
30
|
+
|
|
31
|
+
## Why an execution boundary
|
|
6
32
|
|
|
7
|
-
|
|
33
|
+
Model-level controls shape what an agent says. They cannot prove, after the fact, that a specific
|
|
34
|
+
side effect was authorized by a specific policy at the moment it happened. Prompt filtering,
|
|
35
|
+
fine-tuning, and evaluation all sit before the action; the gap is at execution. This package closes
|
|
36
|
+
it structurally:
|
|
37
|
+
|
|
38
|
+
- **The agent's input is only the proposal.** Action, target, and parameters. Tenant, actor,
|
|
39
|
+
downstream system, and credentials come from trusted server configuration and cannot be injected.
|
|
40
|
+
- **The decision is made elsewhere.** Decionis evaluates the canonical intent hash and returns
|
|
41
|
+
`ALLOW`, `ESCALATE`, or `BLOCK` with a decision identifier and a Decision Dossier identifier.
|
|
42
|
+
- **Approval is evidence, never authority.** Presence proves that a real person approved that exact
|
|
43
|
+
intent. Decionis verifies the receipt and re-evaluates current policy before any grant exists.
|
|
44
|
+
- **Execution consumes a grant, not a callback.** `SafeExecutor` accepts a captured intent and a
|
|
45
|
+
decision. It claims the grant atomically, then invokes a handler from a sealed registry.
|
|
46
|
+
- **Everything else fails closed.** A network error, a malformed response, a missing grant, an
|
|
47
|
+
expired intent, a replayed token, or a binding mismatch all result in no execution.
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- Node.js 22.14 or later. The package is ESM-only and ships its own TypeScript declarations.
|
|
52
|
+
- A server-side process that holds the Decionis credentials. Never load this package into a
|
|
53
|
+
browser, an agent sandbox, or any runtime the model can influence.
|
|
54
|
+
- `zod` v4 for handler parameter schemas (installed as a dependency).
|
|
55
|
+
|
|
56
|
+
## Install
|
|
8
57
|
|
|
9
58
|
```bash
|
|
10
59
|
npm install @decionis/agent-safe-pipeline
|
|
11
60
|
```
|
|
12
61
|
|
|
13
|
-
|
|
62
|
+
Stable releases publish under the `latest` tag with npm provenance. Prereleases publish under the
|
|
63
|
+
`next` tag and are never installed by default:
|
|
14
64
|
|
|
15
65
|
```bash
|
|
16
|
-
npm install @decionis/agent-safe-pipeline@
|
|
66
|
+
npm install @decionis/agent-safe-pipeline@next
|
|
17
67
|
```
|
|
18
68
|
|
|
19
|
-
|
|
69
|
+
Decionis credentials belong only in the trusted executor process:
|
|
20
70
|
|
|
21
71
|
```text
|
|
22
72
|
DECIONIS_API_URL=https://api.decionis.com
|
|
23
73
|
DECIONIS_API_KEY=server-side-secret
|
|
24
74
|
```
|
|
25
75
|
|
|
76
|
+
`DecionisGate` and `DecionisGrantVerifier` accept `apiKey` as a string or as a function read at
|
|
77
|
+
each request. A deployment whose credential rotates inside a process's life gives the function: the
|
|
78
|
+
next request carries the new value, a request already in flight keeps the one it sent, and nothing
|
|
79
|
+
has to be rebuilt to make that true. A credential that does not rotate stays a string.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const gate = new DecionisGate({
|
|
83
|
+
baseUrl: process.env.DECIONIS_API_URL!,
|
|
84
|
+
apiKey: () => secrets.current("DECIONIS_API_KEY"),
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Quick start: enforcement
|
|
89
|
+
|
|
90
|
+
The complete production path in one file. The proposal comes from the agent; everything else comes
|
|
91
|
+
from trusted configuration.
|
|
92
|
+
|
|
26
93
|
```ts
|
|
27
94
|
import {
|
|
28
95
|
ActionRegistry,
|
|
@@ -33,17 +100,37 @@ import {
|
|
|
33
100
|
} from "@decionis/agent-safe-pipeline";
|
|
34
101
|
import { z } from "zod";
|
|
35
102
|
|
|
103
|
+
// 1. Capture the exact proposal. The agent supplies only action, target, and parameters.
|
|
104
|
+
const captured = new IntentCapture().capture(
|
|
105
|
+
{
|
|
106
|
+
action: "refund_order",
|
|
107
|
+
target: "shopify:order:1001",
|
|
108
|
+
parameters: { orderId: "1001", amountMinor: 35_000 },
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
tenantId: config.tenantId,
|
|
112
|
+
actor: { id: "refund-agent", type: "AI_AGENT" },
|
|
113
|
+
downstreamTarget: { system: "shopify", operation: "refund", environment: "production" },
|
|
114
|
+
idempotencyKey: "refund-1001-v1",
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// 2. Ask Decionis. The gate never returns an executable decision without a grant.
|
|
36
119
|
const gate = new DecionisGate({
|
|
37
120
|
baseUrl: process.env.DECIONIS_API_URL!,
|
|
38
121
|
apiKey: process.env.DECIONIS_API_KEY!,
|
|
39
122
|
});
|
|
40
|
-
const
|
|
123
|
+
const decision = await gate.evaluate(captured);
|
|
124
|
+
|
|
125
|
+
// 3. Register trusted handlers once, then seal the registry so nothing can be added at runtime.
|
|
41
126
|
const registry = new ActionRegistry()
|
|
42
127
|
.register("refund_order", {
|
|
43
128
|
parametersSchema: z.object({ orderId: z.string(), amountMinor: z.number().int() }).strict(),
|
|
44
129
|
execute: ({ parameters }) => shopify.refund(parameters),
|
|
45
130
|
})
|
|
46
131
|
.seal();
|
|
132
|
+
|
|
133
|
+
// 4. Execute only through a claimed single-use grant bound to this intent.
|
|
47
134
|
const executor = new SafeExecutor(
|
|
48
135
|
registry,
|
|
49
136
|
new DecionisGrantVerifier({
|
|
@@ -51,16 +138,390 @@ const executor = new SafeExecutor(
|
|
|
51
138
|
apiKey: process.env.DECIONIS_API_KEY!,
|
|
52
139
|
}),
|
|
53
140
|
);
|
|
54
|
-
const result = await executor.run(captured,
|
|
141
|
+
const result = await executor.run(captured, decision);
|
|
142
|
+
|
|
143
|
+
if (result.outcome === "COMPLETED") {
|
|
144
|
+
// result.result is the handler's return value.
|
|
145
|
+
// result.authorization carries the consumed { decisionId, dossierId, grantId, intentHash }.
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The executor validates parameters against the handler's schema before the grant is claimed, and the
|
|
150
|
+
grant is claimed before the handler runs. If either step fails, the handler is never invoked.
|
|
151
|
+
|
|
152
|
+
The trusted context also accepts an optional `expectedEffectDigest` (`sha256:` plus 64 lowercase hex):
|
|
153
|
+
a digest-only commitment to the downstream state predicted before dispatch. It is bound into the
|
|
154
|
+
canonical intent hash and into the signed grant, and `DecionisGrantVerifier` refuses the authorization
|
|
155
|
+
unless the returned grant echoes exactly that digest. The agent proposal can never carry it, and an
|
|
156
|
+
intent that omits it hashes byte-identically to before the field existed. After the attempt, a trusted
|
|
157
|
+
runtime that observed the effect may pass an `AuthorityEffectEvidence` record as `effectEvidence` to
|
|
158
|
+
`DecionisGrantVerifier.finalize`, and read the authority's own `AuthorityEffectReport` back through
|
|
159
|
+
`effectReport(authorization)`. See
|
|
160
|
+
[execution intent](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/execution-intent.md)
|
|
161
|
+
and [execution outcomes](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/execution-outcomes.md).
|
|
162
|
+
|
|
163
|
+
## Outcomes
|
|
164
|
+
|
|
165
|
+
Decionis returns one of three verdicts. The executor turns a verdict into exactly one execution
|
|
166
|
+
outcome.
|
|
167
|
+
|
|
168
|
+
| Verdict | Executor behavior |
|
|
169
|
+
| ------------------------------------- | ----------------------------------------------------------------------- |
|
|
170
|
+
| `ALLOW` with a valid single-use grant | Claim the grant atomically, then invoke the registered handler |
|
|
171
|
+
| `ESCALATE` | Stop. Resolve a DIRECT or MANAGED Presence escalation, then re-evaluate |
|
|
172
|
+
| `BLOCK`, any error, any mismatch | Fail closed. The handler is never invoked |
|
|
173
|
+
|
|
174
|
+
`SafeExecutor.run` resolves to a discriminated result rather than throwing:
|
|
175
|
+
|
|
176
|
+
| `outcome` | Meaning |
|
|
177
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
178
|
+
| `COMPLETED` | The grant was consumed and the handler returned. `result` holds its value. |
|
|
179
|
+
| `BLOCKED` | Nothing ran. `reason` names the refusal: a non-authoritative or non-`ALLOW` decision, a missing or invalid grant, an intent binding or conformance failure, or an unavailable audit sink. |
|
|
180
|
+
| `FAILED_BEFORE_DISPATCH` | The grant was consumed but the handler failed before reaching the provider. Safe to reason about. |
|
|
181
|
+
| `DEFINITELY_NOT_EXECUTED` | The provider was called and refused deterministically. `reason` is its own code. Nothing was effected and there is nothing to reconcile. |
|
|
182
|
+
| `UNKNOWN_AFTER_DISPATCH` | The provider was called and its outcome is unknown. A `recovery` reference supports reconciliation. |
|
|
183
|
+
|
|
184
|
+
A handler reports that last-but-one case by throwing `ProviderRefusal` from inside `dispatch.run`,
|
|
185
|
+
with the provider's own reason code. Only a deterministic refusal belongs in it: a timeout, a 5xx
|
|
186
|
+
or an unreadable answer is not a refusal, and reporting one as a refusal would turn "nobody knows"
|
|
187
|
+
into "definitely not".
|
|
188
|
+
|
|
189
|
+
Every outcome that consumed a grant also reports `finalization` (`RECORDED`, `PENDING`, or
|
|
190
|
+
`UNSUPPORTED`). The executor records `COMMITTED`, `FAILED`, or `INDETERMINATE` with Decionis after
|
|
191
|
+
the attempt so commit evidence joins the Decision Dossier chain. Finalization is evidence, never
|
|
192
|
+
authority: it cannot change `outcome` or `executed`.
|
|
193
|
+
|
|
194
|
+
### What each record establishes
|
|
195
|
+
|
|
196
|
+
Fluent summaries lose these distinctions first. Each row names the record or state, what it
|
|
197
|
+
establishes, and what it does not.
|
|
198
|
+
|
|
199
|
+
| Record or state | What it establishes | What it does not establish |
|
|
200
|
+
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| Captured intent (`IntentCapture`, `intentHash`) | The exact action, target, and parameters the agent proposed, bound to trusted tenant, actor, and downstream context, hashed and expiring | That the agent's facts, identities, or amounts are true; that anything may execute |
|
|
202
|
+
| Verified human approval (Presence `receiptDossierId`) | A named person approved that exact intent hash under the assurance the receipt records | Permission to execute: Decionis re-evaluates policy with the receipt, and only that evaluation can issue a grant |
|
|
203
|
+
| Execution grant (`authorization` on an `ALLOW`) | Permission for one attempt at one intent, claimed once through the `AuthorizationVerifier` immediately before the handler runs | Anything after expiry, for another intent hash, or on a second presentation; a dossier identifier, an invitation link, or an earlier `ALLOW` is not a substitute |
|
|
204
|
+
| Decision Dossier (`decisionId`, `dossierId`) | The record of why Decionis allowed, escalated, or blocked: policy snapshot, inputs, evidence, and grant metadata | An execution credential; proof that the underlying business judgement was right |
|
|
205
|
+
| Single claim, `COMPLETED` | The grant was consumed once and the trusted handler returned a provider result | An exactly-once downstream business effect or independent confirmation of settlement; whether an observation counts as `CONFIRMED` is the authority's judgement, not this package's |
|
|
206
|
+
| `UNKNOWN_AFTER_DISPATCH`, finalized `INDETERMINATE` | Dispatch began and completion could not be proved | Permission to repeat the side effect: reconcile through provider idempotency and read-only lookup, never by a second dispatch |
|
|
207
|
+
| `DEFINITELY_NOT_EXECUTED`, finalized `FAILED` | Dispatch began, the provider refused it deterministically, and nothing was effected | Permission to try again: the refusal was about this attempt, and another needs a fresh decision and a fresh grant |
|
|
208
|
+
| Shadow observation (`ShadowPipeline`, `mode: "SHADOW"`) | What Decionis would have decided about an action that already ran: a verdict and a dossier, no grant | Enforcement, a grant, or a no-write test environment; the production write happened as before |
|
|
209
|
+
| Library boundary (this package) | Intent capture, the gate, verification, and claim-before-handler dispatch inside the trusted integration | Host isolation, IAM, network egress, credential storage, or incident response; see the [threat model](https://github.com/decionis/agent-safe-pipeline/blob/master/THREAT-MODEL.md) and [trust boundary](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/trust-boundary.md) |
|
|
210
|
+
| Trusted executor (`createTrustedExecutor`) | What one process verifies about itself and enforces at its own door: the host posture `HostPosture` can observe, caller principals with roles and their own credentials, egress sealed to the origins `EgressPolicy` was configured with, a durable attempt journal reconciled by `StartupReconciler`, the ceilings in `HardLimits`, BEAP-vocabulary effect evidence, `HaltSwitch`, and hash-chained evidence with an offline-verifiable export | Node or kernel isolation, a CNI actually enforcing the NetworkPolicies the kit declares, an HSM or KMS, the authority's policy, or a bank's core correctness |
|
|
211
|
+
| Executor evidence bundle (`agent-safe.evidence-bundle/1`) | What one executor process can say about an incident: both hash-chained streams as it still held them, the open attempts, the posture by check, the chain heads, a configuration digest, and every file's own digest | Origin, unless a signature over the manifest verifies against a key the reader brought; completeness, since it carries a bounded window and says how many lines it dropped; and it holds no parameter, no provider body, no secret and no digest of one |
|
|
212
|
+
|
|
213
|
+
The sequence that produces both records, and two synthetic records side by side, are in
|
|
214
|
+
[Decision Dossiers](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/decision-dossiers.md).
|
|
215
|
+
|
|
216
|
+
## Human approval through Presence
|
|
217
|
+
|
|
218
|
+
When policy escalates, a person must approve that exact intent with independently signed evidence.
|
|
219
|
+
Presence delivers the request to an enrolled device and returns a receipt bound to the intent hash.
|
|
220
|
+
Presence never authorizes execution; Decionis verifies the receipt and re-evaluates policy. The
|
|
221
|
+
package supports two integration levels, and the executor's grant path is identical in both.
|
|
222
|
+
|
|
223
|
+
| Mode | Who coordinates Presence | Credentials in the executor | Entry point |
|
|
224
|
+
| --------- | ------------------------ | --------------------------- | ---------------------------------------------------- |
|
|
225
|
+
| `DIRECT` | Your trusted executor | Decionis and Presence | `PresenceApprovalCoordinator` |
|
|
226
|
+
| `MANAGED` | Decionis | Decionis only | `DecionisGate.evaluate` with an `escalation` request |
|
|
227
|
+
|
|
228
|
+
In MANAGED mode, pass routing and ceremony constraints outside the canonical intent, then poll
|
|
229
|
+
Decionis only:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
const pending = await gate.evaluate(captured, undefined, {
|
|
233
|
+
escalation: {
|
|
234
|
+
mode: "MANAGED",
|
|
235
|
+
approver: { principal_id: approverId, role_id: "APPROVER" },
|
|
236
|
+
verification_requirements: { methods: ["WEBAUTHN"], level: "HIGH_CONFIDENCE" },
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
// pending.verdict === "ESCALATE"; pending.managedEscalation is set; no grant exists yet.
|
|
240
|
+
|
|
241
|
+
const authorized = await gate.waitForAuthorization(captured, pending, { signal });
|
|
242
|
+
const result = await executor.run(captured, authorized);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`waitForAuthorization` polls with capped exponential backoff and bounded jitter, and stops at the
|
|
246
|
+
intent or escalation expiry. It returns a normal `ALLOW` decision with a grant only after Decionis
|
|
247
|
+
has verified the Presence evidence and re-evaluated current policy. Approval cannot revive an intent
|
|
248
|
+
after it expires. Presence transport or schema failures and Decionis re-authorization failures
|
|
249
|
+
return stable fail-closed decisions; raw downstream error text never reaches the caller.
|
|
250
|
+
|
|
251
|
+
## Shadow mode
|
|
252
|
+
|
|
253
|
+
Measure before you enforce. `ShadowPipeline` wraps an execution path you already run and records
|
|
254
|
+
what Decionis would have decided, without the ability to stop, delay, or alter it.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { DecionisGate, ShadowPipeline } from "@decionis/agent-safe-pipeline";
|
|
258
|
+
|
|
259
|
+
const shadow = new ShadowPipeline(new DecionisGate({ baseUrl, apiKey, mode: "SHADOW" }), {
|
|
260
|
+
timeoutMs: 2_000,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const run = await shadow.observe(captured, () => existingRefund(order));
|
|
264
|
+
// run.production is your unchanged result, available as soon as production settles.
|
|
265
|
+
const observation = await run.observation;
|
|
266
|
+
// The observation runs under its own timeout and never rejects; it reports the verdict
|
|
267
|
+
// Decionis would have returned, the dossier identifier, and whether a grant was discarded.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
A shadow observation carries no grant, is structurally distinct from a `GateDecision`, and is
|
|
271
|
+
rejected by `SafeExecutor` at runtime. See
|
|
272
|
+
[shadow mode](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/shadow-mode.md).
|
|
273
|
+
|
|
274
|
+
## Adoption path
|
|
275
|
+
|
|
276
|
+
The same `IntentCapture`, `ActionRegistry`, and handler code carry through every stage. Nothing is
|
|
277
|
+
rewritten between them.
|
|
278
|
+
|
|
279
|
+
| Stage | Authority | What it proves |
|
|
280
|
+
| ----------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
281
|
+
| Development | `createFixtureAuthorityPair` (refuses `NODE_ENV=production`) | The intent, registry, and executor wiring is correct |
|
|
282
|
+
| Shadow | `ShadowPipeline` over `DecionisGate` with `mode: "SHADOW"` | What Decionis would have decided about actions that already run; no grant issued |
|
|
283
|
+
| Enforcement | `DecionisGate` plus `DecionisGrantVerifier` in `SafeExecutor` | Nothing runs without an independent decision and a consumed single-use grant |
|
|
284
|
+
|
|
285
|
+
### Selecting the gate from the environment
|
|
286
|
+
|
|
287
|
+
`createGate` moves an integration between those stages with configuration alone. It takes the
|
|
288
|
+
authority and verifier you already run, and reads one variable to decide whether Decionis runs
|
|
289
|
+
beside them:
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import { createFixtureAuthorityPair, createGate } from "@decionis/agent-safe-pipeline";
|
|
293
|
+
|
|
294
|
+
const gate = createGate({
|
|
295
|
+
local: createFixtureAuthorityPair(() => "BLOCK", { unsafeAllowDevelopmentFixture: true }),
|
|
296
|
+
tenantId: "00000000-0000-4000-8000-000000000001",
|
|
297
|
+
});
|
|
298
|
+
const captured = new IntentCapture().capture(proposal, { tenantId: gate.tenantId, ...trusted });
|
|
299
|
+
const decision = await gate.authority.evaluate(captured);
|
|
300
|
+
const result = await new SafeExecutor(registry, gate.verifier).run(captured, decision);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
| Variable | Default | Effect |
|
|
304
|
+
| ---------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
305
|
+
| `DECIONIS_API_KEY` | unset | Unset: `gate.authority` and `gate.verifier` are the `local` objects themselves, and no client is constructed. Set: `DecionisGate` runs beside `local` through `ShadowGate`. |
|
|
306
|
+
| `DECIONIS_TENANT_ID` | required with the key | The key's organization. Decionis binds every intent to it, so `gate.tenantId` returns it for the capture; without the key, `gate.tenantId` is the `tenantId` you passed. |
|
|
307
|
+
| `DECIONIS_MODE` | `SHADOW` | `SHADOW`: the local decision governs execution and the hosted one is recorded on `decision.hosted`. `ENFORCEMENT`: the hosted decision governs, claimed through `DecionisGrantVerifier`; local can only tighten. |
|
|
308
|
+
| `DECIONIS_API_URL` | `https://api.decionis.com` | HTTPS only, unless `DECIONIS_ALLOW_INSECURE_LOOPBACK=true` names a loopback double. |
|
|
309
|
+
| `DECIONIS_TIMEOUT_MS` | `DecionisGate`'s default | Budget for the hosted call. A call past it is recorded as fail-closed. |
|
|
310
|
+
| `DECIONIS_ALLOW_INSECURE_LOOPBACK` | unset | `true` permits `http://127.0.0.1` for `LocalAuthority`. |
|
|
311
|
+
|
|
312
|
+
`ShadowGate` never returns a decision less restrictive than the local authority's, in either mode. A
|
|
313
|
+
hosted timeout, network error, non-2xx response, malformed body, or binding mismatch is recorded on
|
|
314
|
+
`decision.hosted` as `failClosed` with verdict `BLOCK`: in `SHADOW` that changes nothing about
|
|
315
|
+
execution, in `ENFORCEMENT` it blocks. A hosted variable that cannot be honoured (`DECIONIS_MODE`
|
|
316
|
+
outside `SHADOW` and `ENFORCEMENT`, a missing `DECIONIS_TENANT_ID`, a non-HTTPS URL) throws at
|
|
317
|
+
construction rather than falling back to local, so a misconfiguration is never mistaken for hosted
|
|
318
|
+
mode.
|
|
319
|
+
|
|
320
|
+
`DecionisGate` sends `User-Agent: agent-safe-pipeline/<version>` on every call, and `source`
|
|
321
|
+
(`{ repo, example }`, on `createGate` or the gate itself) is appended to it as a comment. It is
|
|
322
|
+
client identification for the authority's own accounting, never decision input, and it is sent only
|
|
323
|
+
when a call is made at all.
|
|
324
|
+
|
|
325
|
+
`printDecision(decision, { out })` writes what Decionis said, when it was asked, and nothing when
|
|
326
|
+
it was not: the governing verdict, the hosted verdict with its standing (`governs`, `recorded
|
|
327
|
+
beside the local verdict`, or `failed closed`), the dossier identifier, the page that verifies it
|
|
328
|
+
when the authority attached one (`decision.hosted.verificationUrl`), and the command that verifies
|
|
329
|
+
it offline. Pass `out: process.stderr` where stdout is a transport, as in a stdio MCP server, and
|
|
330
|
+
`verifyCommand` to name your own verification step; the default names this repository's
|
|
331
|
+
`pnpm decionis:verify <dossier-id>`, which fetches the signed record with your key and checks its
|
|
332
|
+
Ed25519 proof bundle against the authority's public JWKS offline.
|
|
333
|
+
|
|
334
|
+
### One variable, a key issued in the run
|
|
335
|
+
|
|
336
|
+
`createHostedGate` is `createGate` with one more way onto Decionis, for the moment a developer has
|
|
337
|
+
nothing but a clone:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import { createHostedGate, printHostedOutcome } from "@decionis/agent-safe-pipeline";
|
|
341
|
+
|
|
342
|
+
const gate = await createHostedGate({
|
|
343
|
+
local: createFixtureAuthorityPair(() => "BLOCK", { unsafeAllowDevelopmentFixture: true }),
|
|
344
|
+
tenantId: "00000000-0000-4000-8000-000000000001",
|
|
345
|
+
source: { repo: "owner/name", example: "basic-agent", surface: "github" },
|
|
346
|
+
});
|
|
347
|
+
const decision = await gate.authority.evaluate(captured);
|
|
348
|
+
await printHostedOutcome(gate, decision);
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
| `DECIONIS_HOSTED` | `DECIONIS_API_KEY` | What runs |
|
|
352
|
+
| ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
353
|
+
| unset | unset | The local pair, untouched; `printHostedOutcome` writes one hint line. |
|
|
354
|
+
| any | set | Exactly `createGate`: the key and `DECIONIS_TENANT_ID` from the environment, in `DECIONIS_MODE`. |
|
|
355
|
+
| `1` | unset | The credential this user keeps for this authority (`agentsafe login`, or an earlier run), else a free provisional workspace minted now from `POST /v1/public/agents/provision`, stored for the next run, and named on standard error once. |
|
|
356
|
+
|
|
357
|
+
A provisional workspace needs no account, no email and no card; its key evaluates in `SHADOW`
|
|
358
|
+
only, so the local verdict still governs and the hosted decision and its signed Decision Dossier
|
|
359
|
+
are recorded beside it. The credential lives in `$AGENTSAFE_HOME`, else
|
|
360
|
+
`$XDG_CONFIG_HOME/agentsafe`, else `~/.config/agentsafe/credentials.json`, readable by its owner
|
|
361
|
+
alone, the same file `agentsafe login` writes; `NODE_ENV=production` refuses the whole path, as
|
|
362
|
+
it refuses every stored login. `resolveHostedCredentials` is the same resolution for a process
|
|
363
|
+
that is not a gate, such as the trusted executor. The provisioning call carries the client
|
|
364
|
+
identification (`repo`, `example`, `surface`) in its `User-Agent`, and nothing else about the
|
|
365
|
+
machine.
|
|
366
|
+
|
|
367
|
+
`printHostedOutcome(gate, decision, { out })` is how an example ends: `printDecision`, then the
|
|
368
|
+
signed record itself, fetched with the run's own key from `GET /v1/protocol/dossiers/{id}`
|
|
369
|
+
(`gate.fetchDossier`) and shown by its proof: the algorithm, the key, when it was issued, how many
|
|
370
|
+
artifacts it covers, and the issuer tier, `provisional_anonymous` for a workspace without an
|
|
371
|
+
account. `fetchSignedDossier`, `summarizeDossier` and `printSignedDossier` are the parts.
|
|
372
|
+
|
|
373
|
+
## Local testing
|
|
374
|
+
|
|
375
|
+
`@decionis/agent-safe-pipeline/testing` ships `LocalPresence` and `LocalAuthority`: loopback doubles
|
|
376
|
+
that the production clients talk to unchanged. They enforce the structural intent-hash binding,
|
|
377
|
+
verify receipts the way Decionis does, issue single-use grants, orchestrate managed escalations, and
|
|
378
|
+
record finalization. The person's ceremony becomes a method call.
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { DecionisGate, DecionisGrantVerifier } from "@decionis/agent-safe-pipeline";
|
|
382
|
+
import {
|
|
383
|
+
LocalAuthority,
|
|
384
|
+
LocalPresence,
|
|
385
|
+
LOCAL_AUTHORITY_API_KEY,
|
|
386
|
+
} from "@decionis/agent-safe-pipeline/testing";
|
|
387
|
+
|
|
388
|
+
const presence = new LocalPresence({ autoComplete: "MANUAL", roles: { "synthetic-cro": "CRO" } });
|
|
389
|
+
const authority = new LocalAuthority({ presence });
|
|
390
|
+
await presence.start();
|
|
391
|
+
await authority.start();
|
|
392
|
+
|
|
393
|
+
const gate = new DecionisGate({
|
|
394
|
+
baseUrl: authority.baseUrl,
|
|
395
|
+
apiKey: LOCAL_AUTHORITY_API_KEY,
|
|
396
|
+
allowInsecureLoopback: true,
|
|
397
|
+
});
|
|
398
|
+
// ... evaluate, then complete the ceremony with presence.approve(requestId)
|
|
399
|
+
// and assert on grants, receipts, and recorded commits.
|
|
55
400
|
```
|
|
56
401
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
402
|
+
Both doubles bind to `127.0.0.1` on an ephemeral port and refuse to construct under
|
|
403
|
+
`NODE_ENV=production`. The testing entry also exports the development fixture primitives
|
|
404
|
+
(`createFixtureAuthorityPair`, `FixtureDecisionAuthority`, `FixtureAuthorizationVerifier`,
|
|
405
|
+
`InMemoryReplayStore`). Those remain available at the package root until 1.0; new code should import
|
|
406
|
+
them from the testing entry. See
|
|
407
|
+
[local testing](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/local-testing.md).
|
|
408
|
+
|
|
409
|
+
## API overview
|
|
410
|
+
|
|
411
|
+
| Concern | Exports | Role |
|
|
412
|
+
| -------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
413
|
+
| Intent | `IntentCapture`, `CanonicalIntentHasher`, `ExecutionIntentSchema`, `AgentProposalSchema` | Build the immutable `agent-safe.intent/1` binding and its canonical SHA-256 hash |
|
|
414
|
+
| Decision | `DecionisGate`, `DecisionAuthority`, `GateDecision`, `FailClosedDecision` | Obtain an independent `ALLOW` / `ESCALATE` / `BLOCK` decision with dossier identifiers |
|
|
415
|
+
| Selection | `createGate`, `ShadowGate`, `SelectedGate`, `HostedEvaluation`, `printDecision` | Choose local, shadow, or enforcement from the environment; combine and report the two verdicts |
|
|
416
|
+
| Human approval | `PresenceApprovalCoordinator`, `ManagedEscalationRequest`, `HumanApprovalEvidence` | Coordinate DIRECT Presence ceremonies or request MANAGED orchestration by Decionis |
|
|
417
|
+
| Execution | `SafeExecutor`, `ActionRegistry`, `DecionisGrantVerifier`, `AuthorizationVerifier`, `ReplayStore` | Claim the single-use grant, validate parameters, invoke a sealed handler, finalize the attempt |
|
|
418
|
+
| Effect | `AuthorityEffectEvidence`, `AuthorityEffectReport`, `DecionisGrantVerifier.effectReport` | Forward a trusted runtime's downstream observation on finalize and read the authority's answer |
|
|
419
|
+
| Observation | `ShadowPipeline`, `ShadowObservation` | Record what the authority would have decided without granting execution |
|
|
420
|
+
| Audit | `AuditRecorder`, `AuditEventV1`, `AuditSink` | Emit immutable, redacted lifecycle records through one bounded sink call |
|
|
421
|
+
| Testing | `LocalPresence`, `LocalAuthority`, `createFixtureAuthorityPair` (from `/testing`) | Loopback doubles and fixture authorities for development and CI |
|
|
422
|
+
|
|
423
|
+
The seam between this package and Decionis is two interfaces, `DecisionAuthority` and
|
|
424
|
+
`AuthorizationVerifier`, plus a published OpenAPI contract. Anyone can implement the interfaces; the
|
|
425
|
+
library checks no plan, key, or entitlement.
|
|
426
|
+
|
|
427
|
+
## Production invariants
|
|
428
|
+
|
|
429
|
+
1. Agent input contains only the proposed action, target, and parameters. Tenant, actor, downstream
|
|
430
|
+
target, and credentials come from trusted runtime configuration.
|
|
431
|
+
2. The exact canonical intent is hashed and expires quickly.
|
|
432
|
+
3. Decionis decides independently. Network errors, malformed responses, missing grants, and binding
|
|
433
|
+
mismatches fail closed.
|
|
434
|
+
4. Presence proves a human approved that exact intent. It never authorizes execution; Decionis
|
|
435
|
+
verifies the receipt and re-evaluates policy.
|
|
436
|
+
5. The grant is bound to the intent, decision, audience, and expiry, and is claimed atomically before
|
|
437
|
+
the handler runs. The attempt is finalized afterwards as evidence, never as authority.
|
|
438
|
+
6. Downstream credentials exist only behind the trusted executor.
|
|
439
|
+
7. Every decision is evidence-bearing. An `ALLOW` without a dossier identifier or grant is refused
|
|
440
|
+
as non-executable. A dossier identifier is never an execution credential.
|
|
441
|
+
|
|
442
|
+
Read the [trust boundary](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/trust-boundary.md)
|
|
443
|
+
and the [threat model](https://github.com/decionis/agent-safe-pipeline/blob/master/THREAT-MODEL.md)
|
|
444
|
+
before integrating a real downstream API.
|
|
445
|
+
|
|
446
|
+
## Assurance and supply chain
|
|
447
|
+
|
|
448
|
+
The reviewer's route through all of it, with what each piece of evidence establishes and what it
|
|
449
|
+
does not, is
|
|
450
|
+
[EVALUATION-PATH.md](https://github.com/decionis/agent-safe-pipeline/blob/master/EVALUATION-PATH.md).
|
|
451
|
+
|
|
452
|
+
- **Provenance.** Every release is published through npm trusted publishing with a provenance
|
|
453
|
+
attestation, from a keyless-signed release tag, and archived under Zenodo concept DOI
|
|
454
|
+
[`10.5281/zenodo.22312955`](https://doi.org/10.5281/zenodo.22312955).
|
|
455
|
+
- **Release evidence.** Each GitHub release carries the tarball, a CycloneDX SBOM, Sigstore
|
|
456
|
+
provenance and SBOM attestations, and a checksum file. See
|
|
457
|
+
[reproducible builds](https://github.com/decionis/agent-safe-pipeline/blob/master/docs/reproducible-builds.md).
|
|
458
|
+
- **Testing.** Coverage gates of 90% lines, functions, and statements and 85% branches; mutation
|
|
459
|
+
testing on the trust boundary; deterministic property-based fuzzing of canonical intent handling;
|
|
460
|
+
a loopback wire-contract harness that exercises the packed package over real HTTP.
|
|
461
|
+
- **Adversarial proof.** The
|
|
462
|
+
[golden adversarial demo](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/golden-adversarial-demo)
|
|
463
|
+
runs one legitimate path and eight attacks against the same boundary, offline, and exits 0 only
|
|
464
|
+
when exactly one action executes.
|
|
465
|
+
- **Scanning.** CodeQL, secret scanning, OpenSSF Scorecard, and OpenSSF Best Practices, with
|
|
466
|
+
separate production and toolchain dependency audits. The control-to-artifact map is in
|
|
467
|
+
[SECURITY-EVIDENCE.md](https://github.com/decionis/agent-safe-pipeline/blob/master/SECURITY-EVIDENCE.md).
|
|
468
|
+
|
|
469
|
+
## Examples
|
|
470
|
+
|
|
471
|
+
Runnable, offline, and fixture-backed unless noted. Each one uses this package unchanged.
|
|
472
|
+
|
|
473
|
+
- [`basic-agent`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/basic-agent): the smallest `BLOCK` flow.
|
|
474
|
+
- [`shopify-refund-agent`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/shopify-refund-agent): amount-based `ALLOW` / `ESCALATE` / `BLOCK`.
|
|
475
|
+
- [`github-deploy-agent`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/github-deploy-agent): environment and force-push controls.
|
|
476
|
+
- [`procurement-agent`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/procurement-agent): an in-budget request held by policy.
|
|
477
|
+
- [`mcp-tool-gate`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/mcp-tool-gate): a real stdio MCP server with a governed tool.
|
|
478
|
+
- [`local-escalation`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/local-escalation): DIRECT and MANAGED Presence escalation against loopback doubles.
|
|
479
|
+
- [`presence-live-approval`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/presence-live-approval): DIRECT Presence enforcement against the real services with a FIDO2 or FIDO2-plus-liveness ceremony (needs credentials).
|
|
480
|
+
- [`presence-managed-approval`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/presence-managed-approval): Decionis-managed Presence orchestration against the real services (needs credentials).
|
|
481
|
+
- [`golden-adversarial-demo`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/golden-adversarial-demo): one golden path, eight attacks, zero unauthorized executions.
|
|
482
|
+
- [`whisper-boundary-demo`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/whisper-boundary-demo): the same proof for a shopping agent — six attacks, zero unauthorized effects.
|
|
483
|
+
- [`crm-outreach-demo`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/crm-outreach-demo): who can approve a sales agent's CRM update or outbound message — six attacks, a lost provider response reconciled once, zero unauthorized effects.
|
|
484
|
+
- [`trusted-executor`](https://github.com/decionis/agent-safe-pipeline/tree/master/examples/trusted-executor): the proof of `@decionis/agentsafe`, the execution boundary as one deployable process — an HTTP trusted executor in front of these components — over real HTTP against the loopback doubles, and the adopter's template; the image, Kubernetes manifest and shadow-to-enforcement runbook are in the repository's [deployment kit](https://github.com/decionis/agent-safe-pipeline/blob/master/deploy/README.md).
|
|
485
|
+
|
|
486
|
+
## Open core
|
|
487
|
+
|
|
488
|
+
This package and the repository's architecture, intent contract, execution boundary, client
|
|
489
|
+
adapters, audit contract, shadow mode, conformance vectors, and examples are Apache-2.0. The sole
|
|
490
|
+
license exception is the dedicated MIT-licensed Claude Desktop wrapper in
|
|
491
|
+
`packages/commerce-mcp-claude-extension`; the CommerceGate runtime it bundles remains Apache-2.0.
|
|
492
|
+
Decionis operates the policy control plane behind `DecionisGate`: policy evaluation, grant issuance
|
|
493
|
+
and atomic consumption, Decision Dossier signing and retention, and Presence.
|
|
494
|
+
[OPEN-CORE.md](https://github.com/decionis/agent-safe-pipeline/blob/master/OPEN-CORE.md) states the
|
|
495
|
+
boundary and the commitments that keep it stable.
|
|
496
|
+
|
|
497
|
+
## Research
|
|
498
|
+
|
|
499
|
+
Decionis Research defines the architecture, this package demonstrates it as tested code, and the
|
|
500
|
+
Decionis platform operates it as a hosted authority.
|
|
501
|
+
|
|
502
|
+
The banking profile of the protocol, whose reference runtime builds on this package, is published at
|
|
503
|
+
[banking.decionis.com](https://banking.decionis.com) (BEAP v1.0, published 2026-09-15; the profile
|
|
504
|
+
Decionis publishes and implements, not a standard approved by any body). The Commerce Gate this repository's MCP server fronts is at
|
|
505
|
+
[commerce.decionis.com](https://commerce.decionis.com).
|
|
506
|
+
The proof-of-human infrastructure this package's `PresenceApprovalCoordinator` coordinates with is
|
|
507
|
+
described at [decionis.com/proof-of-human-infrastructure](https://decionis.com/proof-of-human-infrastructure)
|
|
508
|
+
and runs at [presence.decionis.com](https://presence.decionis.com); production enforcement there is
|
|
509
|
+
sales-assisted.
|
|
510
|
+
|
|
511
|
+
- Jejelowo, Festus. "The Execution Verifiability Gap: Why Model Governance Cannot Authorize
|
|
512
|
+
Consequential Actions." Decionis Research, version 1.0, 21 August 2026.
|
|
513
|
+
[Canonical article](https://decionis.com/research/execution-verifiability-gap) ·
|
|
514
|
+
[Archival PDF](https://decionis.com/research/execution-verifiability-gap-v1.0.pdf)
|
|
515
|
+
|
|
516
|
+
To cite the software, use the
|
|
517
|
+
[CITATION.cff](https://github.com/decionis/agent-safe-pipeline/blob/master/CITATION.cff) in the
|
|
518
|
+
repository or the Zenodo record above.
|
|
519
|
+
|
|
520
|
+
## Support and license
|
|
62
521
|
|
|
63
|
-
|
|
64
|
-
|
|
522
|
+
- Vulnerabilities: [GitHub private vulnerability reporting](https://github.com/decionis/agent-safe-pipeline/security/advisories/new) or `security@decionis.com`. Never open a public issue for a security report.
|
|
523
|
+
- Everything else: [GitHub Issues](https://github.com/decionis/agent-safe-pipeline/issues).
|
|
524
|
+
- Architecture and full documentation: [Agent-Safe Pipeline README](https://github.com/decionis/agent-safe-pipeline#readme).
|
|
65
525
|
|
|
66
|
-
|
|
526
|
+
Apache-2.0. Trademark terms in
|
|
527
|
+
[TRADEMARKS.md](https://github.com/decionis/agent-safe-pipeline/blob/master/TRADEMARKS.md).
|
package/dist/Index.d.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
export * from "./approval/PresenceApprovalCoordinator.js";
|
|
2
|
+
export * from "./audit/AuditRecorder.js";
|
|
3
|
+
export * from "./decision/CreateGate.js";
|
|
2
4
|
export * from "./decision/DecisionAuthority.js";
|
|
3
5
|
export * from "./decision/DecionisGate.js";
|
|
4
6
|
export * from "./decision/FixtureDecisionAuthority.js";
|
|
7
|
+
export * from "./decision/Provision.js";
|
|
8
|
+
export * from "./decision/ShadowGate.js";
|
|
5
9
|
export * from "./execution/ActionRegistry.js";
|
|
6
10
|
export * from "./execution/AuthorizationVerifier.js";
|
|
7
11
|
export * from "./execution/ReplayStore.js";
|
|
8
12
|
export * from "./execution/SafeExecutor.js";
|
|
13
|
+
export type { ClientSource } from "./http/ClientIdentification.js";
|
|
14
|
+
export * from "./http/StoredCredentials.js";
|
|
9
15
|
export * from "./intent/CanonicalIntentHasher.js";
|
|
10
16
|
export * from "./intent/ExecutionIntent.js";
|
|
11
17
|
export * from "./intent/IntentCapture.js";
|
|
12
18
|
export * from "./intent/JsonValue.js";
|
|
19
|
+
export * from "./report/DecisionReport.js";
|
|
20
|
+
export * from "./report/DossierReport.js";
|
|
21
|
+
export * from "./report/HostedOutcome.js";
|
|
13
22
|
export * from "./shadow/ShadowPipeline.js";
|
|
14
23
|
//# sourceMappingURL=Index.d.ts.map
|
package/dist/Index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Index.d.ts","sourceRoot":"","sources":["../src/Index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"Index.d.ts","sourceRoot":"","sources":["../src/Index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC"}
|
package/dist/Index.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
export * from "./approval/PresenceApprovalCoordinator.js";
|
|
2
|
+
export * from "./audit/AuditRecorder.js";
|
|
3
|
+
export * from "./decision/CreateGate.js";
|
|
2
4
|
export * from "./decision/DecisionAuthority.js";
|
|
3
5
|
export * from "./decision/DecionisGate.js";
|
|
4
6
|
export * from "./decision/FixtureDecisionAuthority.js";
|
|
7
|
+
export * from "./decision/Provision.js";
|
|
8
|
+
export * from "./decision/ShadowGate.js";
|
|
5
9
|
export * from "./execution/ActionRegistry.js";
|
|
6
10
|
export * from "./execution/AuthorizationVerifier.js";
|
|
7
11
|
export * from "./execution/ReplayStore.js";
|
|
8
12
|
export * from "./execution/SafeExecutor.js";
|
|
13
|
+
export * from "./http/StoredCredentials.js";
|
|
9
14
|
export * from "./intent/CanonicalIntentHasher.js";
|
|
10
15
|
export * from "./intent/ExecutionIntent.js";
|
|
11
16
|
export * from "./intent/IntentCapture.js";
|
|
12
17
|
export * from "./intent/JsonValue.js";
|
|
18
|
+
export * from "./report/DecisionReport.js";
|
|
19
|
+
export * from "./report/DossierReport.js";
|
|
20
|
+
export * from "./report/HostedOutcome.js";
|
|
13
21
|
export * from "./shadow/ShadowPipeline.js";
|
|
14
22
|
//# sourceMappingURL=Index.js.map
|
package/dist/Index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Index.js","sourceRoot":"","sources":["../src/Index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"Index.js","sourceRoot":"","sources":["../src/Index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAE5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC"}
|