nexus-control 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. nexus_control-0.6.0/.gitignore +36 -0
  2. nexus_control-0.6.0/ARCHITECTURE.md +178 -0
  3. nexus_control-0.6.0/PKG-INFO +288 -0
  4. nexus_control-0.6.0/QUICKSTART.md +170 -0
  5. nexus_control-0.6.0/README.md +264 -0
  6. nexus_control-0.6.0/docs/ATTESTATION_SCHEMA.md +189 -0
  7. nexus_control-0.6.0/examples/sample_narrative.json +171 -0
  8. nexus_control-0.6.0/nexus_control/__init__.py +70 -0
  9. nexus_control-0.6.0/nexus_control/attestation/__init__.py +63 -0
  10. nexus_control-0.6.0/nexus_control/attestation/_signing.py +371 -0
  11. nexus_control-0.6.0/nexus_control/attestation/flexiflow_adapter.py +218 -0
  12. nexus_control-0.6.0/nexus_control/attestation/intent.py +183 -0
  13. nexus_control-0.6.0/nexus_control/attestation/narrative.py +1262 -0
  14. nexus_control-0.6.0/nexus_control/attestation/queue.py +235 -0
  15. nexus_control-0.6.0/nexus_control/attestation/receipt.py +260 -0
  16. nexus_control-0.6.0/nexus_control/attestation/replay.py +420 -0
  17. nexus_control-0.6.0/nexus_control/attestation/storage.py +241 -0
  18. nexus_control-0.6.0/nexus_control/attestation/worker.py +157 -0
  19. nexus_control-0.6.0/nexus_control/attestation/xrpl/__init__.py +95 -0
  20. nexus_control-0.6.0/nexus_control/attestation/xrpl/adapter.py +379 -0
  21. nexus_control-0.6.0/nexus_control/attestation/xrpl/client.py +130 -0
  22. nexus_control-0.6.0/nexus_control/attestation/xrpl/errors.py +84 -0
  23. nexus_control-0.6.0/nexus_control/attestation/xrpl/exchange_store.py +314 -0
  24. nexus_control-0.6.0/nexus_control/attestation/xrpl/jsonrpc_client.py +220 -0
  25. nexus_control-0.6.0/nexus_control/attestation/xrpl/memo.py +130 -0
  26. nexus_control-0.6.0/nexus_control/attestation/xrpl/signer.py +84 -0
  27. nexus_control-0.6.0/nexus_control/attestation/xrpl/transport.py +234 -0
  28. nexus_control-0.6.0/nexus_control/attestation/xrpl/tx.py +71 -0
  29. nexus_control-0.6.0/nexus_control/audit_export.py +290 -0
  30. nexus_control-0.6.0/nexus_control/audit_package.py +381 -0
  31. nexus_control-0.6.0/nexus_control/bundle.py +433 -0
  32. nexus_control-0.6.0/nexus_control/canonical_json.py +32 -0
  33. nexus_control-0.6.0/nexus_control/decision.py +302 -0
  34. nexus_control-0.6.0/nexus_control/events.py +148 -0
  35. nexus_control-0.6.0/nexus_control/export.py +308 -0
  36. nexus_control-0.6.0/nexus_control/import_.py +359 -0
  37. nexus_control-0.6.0/nexus_control/integrity.py +27 -0
  38. nexus_control-0.6.0/nexus_control/lifecycle.py +524 -0
  39. nexus_control-0.6.0/nexus_control/policy.py +172 -0
  40. nexus_control-0.6.0/nexus_control/store.py +474 -0
  41. nexus_control-0.6.0/nexus_control/template.py +486 -0
  42. nexus_control-0.6.0/nexus_control/tool.py +1447 -0
  43. nexus_control-0.6.0/pyproject.toml +59 -0
  44. nexus_control-0.6.0/schemas/nexus-control.approve.v0.1.json +59 -0
  45. nexus_control-0.6.0/schemas/nexus-control.execute.v0.1.json +59 -0
  46. nexus_control-0.6.0/schemas/nexus-control.inspect.v0.1.json +138 -0
  47. nexus_control-0.6.0/schemas/nexus-control.request.v0.1.json +96 -0
  48. nexus_control-0.6.0/schemas/nexus-control.status.v0.1.json +79 -0
  49. nexus_control-0.6.0/schemas/nexus-control.template.create.v0.1.json +100 -0
  50. nexus_control-0.6.0/schemas/nexus-control.template.get.v0.1.json +57 -0
  51. nexus_control-0.6.0/schemas/nexus-control.template.list.v0.1.json +55 -0
  52. nexus_control-0.6.0/tests/__init__.py +1 -0
  53. nexus_control-0.6.0/tests/test_approval_threshold.py +218 -0
  54. nexus_control-0.6.0/tests/test_attestation_queue.py +544 -0
  55. nexus_control-0.6.0/tests/test_audit_package.py +508 -0
  56. nexus_control-0.6.0/tests/test_decision_replay.py +304 -0
  57. nexus_control-0.6.0/tests/test_exchange_store.py +346 -0
  58. nexus_control-0.6.0/tests/test_execute_links_run.py +371 -0
  59. nexus_control-0.6.0/tests/test_export_import.py +738 -0
  60. nexus_control-0.6.0/tests/test_flexiflow_adapter.py +368 -0
  61. nexus_control-0.6.0/tests/test_inspect.py +327 -0
  62. nexus_control-0.6.0/tests/test_intent.py +264 -0
  63. nexus_control-0.6.0/tests/test_lifecycle.py +794 -0
  64. nexus_control-0.6.0/tests/test_narrative.py +1521 -0
  65. nexus_control-0.6.0/tests/test_policy_compile.py +230 -0
  66. nexus_control-0.6.0/tests/test_receipt.py +402 -0
  67. nexus_control-0.6.0/tests/test_replay.py +431 -0
  68. nexus_control-0.6.0/tests/test_templates.py +621 -0
  69. nexus_control-0.6.0/tests/test_xrpl_adapter.py +277 -0
  70. nexus_control-0.6.0/tests/test_xrpl_dcl.py +581 -0
  71. nexus_control-0.6.0/tests/test_xrpl_jsonrpc.py +525 -0
  72. nexus_control-0.6.0/tests/test_xrpl_memo.py +243 -0
  73. nexus_control-0.6.0/tests/test_xrpl_submit_confirm.py +699 -0
  74. nexus_control-0.6.0/tests/test_xrpl_tx.py +146 -0
@@ -0,0 +1,36 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ *.egg
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Testing
16
+ .pytest_cache/
17
+ .benchmarks/
18
+ htmlcov/
19
+ .coverage
20
+ .coverage.*
21
+ coverage.xml
22
+
23
+ # Linting / Type checking
24
+ .ruff_cache/
25
+ .mypy_cache/
26
+ .pyright/
27
+
28
+ # IDE
29
+ .vscode/
30
+ .idea/
31
+ *.swp
32
+ *.swo
33
+
34
+ # OS
35
+ .DS_Store
36
+ Thumbs.db
@@ -0,0 +1,178 @@
1
+ # Architecture: How Nexus-Control Works
2
+
3
+ ## One Sentence
4
+
5
+ Nexus-Control turns governance + execution into a single, verifiable artifact.
6
+
7
+ Not logs. Not reports. A file you can hash.
8
+
9
+ ## The Core Flow
10
+
11
+ ```
12
+ ┌──────────────────┐
13
+ │ Control Bundle │
14
+ │ (Intent) │
15
+ │ │
16
+ │ - decision │
17
+ │ - policy │
18
+ │ - approvals │
19
+ │ - constraints │
20
+ │ - template │
21
+ └────────┬─────────┘
22
+ │ control_digest
23
+
24
+
25
+ ┌──────────────────┐ ┌──────────────────────────────────┐
26
+ │ Router │ │ Audit Package │
27
+ │ (Execution) │ │ │
28
+ │ │───────▶│ binding_digest = sha256( │
29
+ │ Reference mode: │ │ canonical_json({ │
30
+ │ run_id │ │ package_version, │
31
+ │ router_digest │ │ control_digest, │
32
+ │ │ │ router_digest, │
33
+ │ Embedded mode: │ │ control_router_link_digest │
34
+ │ full bundle │ │ }) │
35
+ │ cross-check │ │ ) │
36
+ └──────────────────┘ └──────────────────────────────────┘
37
+ ▲ ▲
38
+ │ │
39
+ └──── control_router_link_digest ────┘
40
+ (why this execution was allowed)
41
+ ```
42
+
43
+ ## What Each Layer Means
44
+
45
+ ### 1. Control Bundle — What was allowed
46
+
47
+ Governance intent:
48
+ - **Decision**: the request (goal, mode, constraints)
49
+ - **Policy**: approval rules, allowed modes, capabilities
50
+ - **Approvals**: who approved, when, with what comment
51
+ - **Template**: named policy snapshot (if used)
52
+
53
+ Its integrity is captured as `control_digest`.
54
+
55
+ ### 2. Router — What actually ran
56
+
57
+ Execution identity, not a log stream.
58
+
59
+ | Mode | Contains | Use Case |
60
+ |------|----------|----------|
61
+ | **Reference** (default) | `run_id` + `router_digest` | CI, internal systems, continuous operation |
62
+ | **Embedded** | Full router bundle + optional cross-check | Regulators, external auditors, long-term archival |
63
+
64
+ Both modes are cryptographically equivalent at the binding layer.
65
+
66
+ ### 3. Control–Router Link — Why this execution was allowed
67
+
68
+ The most important idea. The link explicitly states:
69
+ **this control bundle authorized that router execution.**
70
+
71
+ This prevents:
72
+ - Replay attacks
73
+ - Execution substitution
74
+ - Post-hoc justification
75
+
76
+ Its integrity is captured as `control_router_link_digest`.
77
+
78
+ ### 4. Binding Digest — The point of no ambiguity
79
+
80
+ ```
81
+ binding_digest = sha256(canonical_json({
82
+ package_version: "0.6",
83
+ control_digest,
84
+ router_digest,
85
+ control_router_link_digest
86
+ }))
87
+ ```
88
+
89
+ If **any** component changes — intent, execution, linkage, or schema —
90
+ the digest breaks. This is the audit truth anchor.
91
+
92
+ ## Verification Model
93
+
94
+ ```
95
+ verify_audit_package()
96
+
97
+ ├─ binding_digest recompute from binding fields
98
+ ├─ control_bundle_digest recompute from control bundle content
99
+ ├─ binding_control_match binding ↔ control bundle consistency
100
+ ├─ binding_router_match binding ↔ router section consistency
101
+ ├─ binding_link_match binding ↔ control-router link consistency
102
+ └─ router_digest embedded router bundle integrity (if applicable)
103
+ ```
104
+
105
+ Properties:
106
+ - **No short-circuiting** — all failures reported
107
+ - **Machine-verifiable** — CI/CD safe
108
+ - **Regulator-readable** — structured JSON output
109
+
110
+ ## Event-Sourced Foundation
111
+
112
+ All state is derived by replaying an immutable event log:
113
+
114
+ ```
115
+ decisions (header)
116
+ └── decision_events (append-only log)
117
+ ├── DECISION_CREATED
118
+ ├── POLICY_ATTACHED
119
+ ├── APPROVAL_GRANTED
120
+ ├── APPROVAL_REVOKED
121
+ ├── EXECUTION_REQUESTED
122
+ ├── EXECUTION_STARTED
123
+ ├── EXECUTION_COMPLETED
124
+ └── EXECUTION_FAILED
125
+ ```
126
+
127
+ No mutable state. No hidden writes. Replay is deterministic.
128
+
129
+ ## System Architecture
130
+
131
+ ```
132
+ ┌─────────────────────────────────────────────────────────┐
133
+ │ nexus-control │
134
+ │ │
135
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │
136
+ │ │ request │ │ approve │ │ execute │ │ audit export │ │
137
+ │ └────┬────┘ └────┬────┘ └────┬────┘ └──────┬───────┘ │
138
+ │ │ │ │ │ │
139
+ │ ▼ ▼ ▼ ▼ │
140
+ │ ┌──────────────────────────────────────────────────┐ │
141
+ │ │ Decision Store (SQLite) │ │
142
+ │ │ - Event log (append-only) │ │
143
+ │ │ - Replay for state │ │
144
+ │ │ - Deterministic digest computation │ │
145
+ │ │ - Export/import with integrity verification │ │
146
+ │ └──────────────────────────────────────────────────┘ │
147
+ │ │ │
148
+ └──────────────────────────┼───────────────────────────────┘
149
+
150
+
151
+ ┌─────────────────┐
152
+ │ nexus-router │
153
+ │ (execution) │
154
+ └─────────────────┘
155
+ ```
156
+
157
+ Control plane stores **links, not copies**. Router remains the flight recorder.
158
+
159
+ ## Design Guarantees
160
+
161
+ | Guarantee | Mechanism |
162
+ |-----------|-----------|
163
+ | Deterministic digests | Canonical JSON (`sort_keys=True, separators=(",",":")`) |
164
+ | Digest schema immutability | Inputs frozen per `package_version` |
165
+ | Tamper evidence | SHA-256 binding across all components |
166
+ | Full failure visibility | `verify_audit_package()` runs all checks |
167
+ | Portable artifacts | JSON bundles with `from_dict()` / `to_dict()` roundtrip |
168
+ | No hidden state | `meta.exported_at` and provenance excluded from digests |
169
+
170
+ ## What This Replaces
171
+
172
+ | Old World | Nexus-Control |
173
+ |-----------|---------------|
174
+ | Logs | Artifacts |
175
+ | Trust | Verification |
176
+ | PDFs | Digests |
177
+ | "Approved in Jira" | Cryptographic linkage |
178
+ | After-the-fact audits | Built-in auditability |
@@ -0,0 +1,288 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexus-control
3
+ Version: 0.6.0
4
+ Summary: Orchestration and approval layer for nexus-router executions
5
+ Project-URL: Homepage, https://github.com/mcp-tool-shop/nexus-control
6
+ Project-URL: Repository, https://github.com/mcp-tool-shop/nexus-control
7
+ Author-email: mcp-tool-shop <64996768+mcp-tool-shop@users.noreply.github.com>
8
+ License-Expression: MIT
9
+ Keywords: approval,audit,mcp,nexus,orchestration
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: nexus-router>=0.1.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pyright>=1.1.350; extra == 'dev'
20
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
21
+ Requires-Dist: pytest>=8.0; extra == 'dev'
22
+ Requires-Dist: ruff>=0.3; extra == 'dev'
23
+ Description-Content-Type: text/markdown
24
+
25
+ > ⚠️ **This repository has moved to [nexus-suite](https://github.com/mcp-tool-shop/nexus-suite)**
26
+ > Source now lives at: `src/nexus-control/`
27
+
28
+ ---
29
+
30
+ # nexus-control
31
+
32
+ **Orchestration and approval layer for nexus-router executions.**
33
+
34
+ A thin control plane that turns "router can execute" into "org can safely decide to execute" — with cryptographic proof.
35
+
36
+ ## Core Promise
37
+
38
+ Every execution is tied to:
39
+ - A **decision** (the request + policy)
40
+ - A **policy** (approval rules, allowed modes, constraints)
41
+ - An **approval trail** (who approved, when, with what comment)
42
+ - A **nexus-router run_id** (for full execution audit)
43
+ - An **audit package** (cryptographic binding of governance to execution)
44
+
45
+ Everything is exportable, verifiable, and replayable.
46
+
47
+ > See [ARCHITECTURE.md](ARCHITECTURE.md) for the full mental model and design guarantees.
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install nexus-control
53
+ ```
54
+
55
+ Or from source:
56
+ ```bash
57
+ git clone https://github.com/mcp-tool-shop/nexus-control
58
+ cd nexus-control
59
+ pip install -e ".[dev]"
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ```python
65
+ from nexus_control import NexusControlTools
66
+ from nexus_control.events import Actor
67
+
68
+ # Initialize (uses in-memory SQLite by default)
69
+ tools = NexusControlTools(db_path="decisions.db")
70
+
71
+ # 1. Create a request
72
+ result = tools.request(
73
+ goal="Rotate production API keys",
74
+ actor=Actor(type="human", id="alice@example.com"),
75
+ mode="apply",
76
+ min_approvals=2,
77
+ labels=["prod", "security"],
78
+ )
79
+ request_id = result.data["request_id"]
80
+
81
+ # 2. Get approvals
82
+ tools.approve(request_id, actor=Actor(type="human", id="alice@example.com"))
83
+ tools.approve(request_id, actor=Actor(type="human", id="bob@example.com"))
84
+
85
+ # 3. Execute (with your router)
86
+ result = tools.execute(
87
+ request_id=request_id,
88
+ adapter_id="subprocess:mcpt:key-rotation",
89
+ actor=Actor(type="system", id="scheduler"),
90
+ router=your_router, # RouterProtocol implementation
91
+ )
92
+
93
+ print(f"Run ID: {result.data['run_id']}")
94
+
95
+ # 4. Export audit package (cryptographic proof of governance + execution)
96
+ audit = tools.export_audit_package(request_id)
97
+ print(audit.data["digest"]) # sha256:...
98
+ ```
99
+
100
+ ## MCP Tools
101
+
102
+ | Tool | Description |
103
+ |------|-------------|
104
+ | `nexus-control.request` | Create an execution request with goal, policy, and approvers |
105
+ | `nexus-control.approve` | Approve a request (supports N-of-M approvals) |
106
+ | `nexus-control.execute` | Execute approved request via nexus-router |
107
+ | `nexus-control.status` | Get request state and linked run status |
108
+ | `nexus-control.inspect` | Read-only introspection with human-readable output |
109
+ | `nexus-control.template.create` | Create a named, immutable policy template |
110
+ | `nexus-control.template.get` | Retrieve a template by name |
111
+ | `nexus-control.template.list` | List all templates with optional label filtering |
112
+ | `nexus-control.export_bundle` | Export a decision as a portable, integrity-verified bundle |
113
+ | `nexus-control.import_bundle` | Import a bundle with conflict modes and replay validation |
114
+ | `nexus-control.export_audit_package` | Export audit package binding governance to execution |
115
+
116
+ ## Audit Packages (v0.6.0)
117
+
118
+ A single JSON artifact that cryptographically binds:
119
+ - **What was allowed** (control bundle)
120
+ - **What actually ran** (router execution)
121
+ - **Why it was allowed** (control-router link)
122
+
123
+ Into one verifiable `binding_digest`.
124
+
125
+ ```python
126
+ from nexus_control import export_audit_package, verify_audit_package
127
+
128
+ # Export
129
+ result = export_audit_package(store, decision_id)
130
+ package = result.package
131
+
132
+ # Verify (6 independent checks, no short-circuiting)
133
+ verification = verify_audit_package(package)
134
+ assert verification.ok
135
+ ```
136
+
137
+ Two router modes:
138
+
139
+ | Mode | Description | Use Case |
140
+ |------|-------------|----------|
141
+ | **Reference** | `run_id` + `router_digest` | CI, internal systems |
142
+ | **Embedded** | Full router bundle included | Regulators, long-term archival |
143
+
144
+ ## Decision Templates (v0.3.0)
145
+
146
+ Named, immutable policy bundles that can be reused across decisions:
147
+
148
+ ```python
149
+ tools.template_create(
150
+ name="prod-deploy",
151
+ actor=Actor(type="human", id="platform-team"),
152
+ min_approvals=2,
153
+ allowed_modes=["dry_run", "apply"],
154
+ require_adapter_capabilities=["timeout"],
155
+ labels=["prod"],
156
+ )
157
+
158
+ # Use template with optional overrides
159
+ result = tools.request(
160
+ goal="Deploy v2.1.0",
161
+ actor=actor,
162
+ template_name="prod-deploy",
163
+ override_min_approvals=3, # Stricter for this deploy
164
+ )
165
+ ```
166
+
167
+ ## Decision Lifecycle (v0.4.0)
168
+
169
+ Computed lifecycle with blocking reasons and timeline:
170
+
171
+ ```python
172
+ from nexus_control import compute_lifecycle
173
+
174
+ lifecycle = compute_lifecycle(decision, events, policy)
175
+
176
+ # Blocking reasons (triage-ladder ordered)
177
+ for reason in lifecycle.blocking_reasons:
178
+ print(f"{reason.code}: {reason.message}")
179
+
180
+ # Timeline with truncation
181
+ for entry in lifecycle.timeline:
182
+ print(f" {entry.seq} {entry.label}")
183
+ ```
184
+
185
+ ## Export/Import Bundles (v0.5.0)
186
+
187
+ Portable, integrity-verified decision bundles:
188
+
189
+ ```python
190
+ # Export
191
+ bundle_result = tools.export_bundle(decision_id)
192
+ bundle_json = bundle_result.data["canonical_json"]
193
+
194
+ # Import with conflict handling
195
+ import_result = tools.import_bundle(
196
+ bundle_json,
197
+ conflict_mode="new_decision_id",
198
+ replay_after_import=True,
199
+ )
200
+ ```
201
+
202
+ Conflict modes: `reject_on_conflict`, `new_decision_id`, `overwrite`
203
+
204
+ ## Data Model
205
+
206
+ ### Event-Sourced Design
207
+
208
+ All state is derived by replaying an immutable event log:
209
+
210
+ ```
211
+ decisions (header)
212
+ └── decision_events (append-only log)
213
+ ├── DECISION_CREATED
214
+ ├── POLICY_ATTACHED
215
+ ├── APPROVAL_GRANTED
216
+ ├── APPROVAL_REVOKED
217
+ ├── EXECUTION_REQUESTED
218
+ ├── EXECUTION_STARTED
219
+ ├── EXECUTION_COMPLETED
220
+ └── EXECUTION_FAILED
221
+ ```
222
+
223
+ ### Policy Model
224
+
225
+ ```python
226
+ Policy(
227
+ min_approvals=2,
228
+ allowed_modes=["dry_run", "apply"],
229
+ require_adapter_capabilities=["timeout"],
230
+ max_steps=50,
231
+ labels=["prod", "finance"],
232
+ )
233
+ ```
234
+
235
+ ### Approval Model
236
+
237
+ - Counted by distinct `actor.id`
238
+ - Can include `comment` and optional `expires_at`
239
+ - Can be revoked (before execution)
240
+ - Execution requires approvals to satisfy policy **at execution time**
241
+
242
+ ## Development
243
+
244
+ ```bash
245
+ # Install dev dependencies
246
+ pip install -e ".[dev]"
247
+
248
+ # Run tests (203 tests)
249
+ pytest
250
+
251
+ # Type check (strict mode)
252
+ pyright
253
+
254
+ # Lint
255
+ ruff check .
256
+ ```
257
+
258
+ ## Project Structure
259
+
260
+ ```
261
+ nexus-control/
262
+ ├── nexus_control/
263
+ │ ├── __init__.py # Public API + version
264
+ │ ├── tool.py # MCP tool entrypoints (11 tools)
265
+ │ ├── store.py # SQLite event store
266
+ │ ├── events.py # Event type definitions
267
+ │ ├── policy.py # Policy validation + router compilation
268
+ │ ├── decision.py # State machine + replay
269
+ │ ├── lifecycle.py # Blocking reasons, timeline, progress
270
+ │ ├── template.py # Named immutable policy templates
271
+ │ ├── export.py # Decision bundle export
272
+ │ ├── import_.py # Bundle import with conflict modes
273
+ │ ├── bundle.py # Bundle types + digest computation
274
+ │ ├── audit_package.py # Audit package types + verification
275
+ │ ├── audit_export.py # Audit package export + rendering
276
+ │ ├── canonical_json.py # Deterministic serialization
277
+ │ └── integrity.py # SHA-256 helpers
278
+ ├── schemas/ # JSON schemas for tool inputs
279
+ ├── tests/ # 203 tests across 9 test files
280
+ ├── ARCHITECTURE.md # Mental model + design guarantees
281
+ ├── QUICKSTART.md
282
+ ├── README.md
283
+ └── pyproject.toml
284
+ ```
285
+
286
+ ## License
287
+
288
+ MIT
@@ -0,0 +1,170 @@
1
+ # Quickstart: nexus-control
2
+
3
+ Get operational in 5 minutes.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install nexus-control
9
+ ```
10
+
11
+ ## The 3-Command Flow
12
+
13
+ ### 1. Create a Decision
14
+
15
+ ```python
16
+ from nexus_control import NexusControlTools
17
+ from nexus_control.events import Actor
18
+
19
+ tools = NexusControlTools(db_path="control.db")
20
+
21
+ result = tools.request(
22
+ goal="rotate production API keys",
23
+ actor=Actor(type="human", id="alice"),
24
+ mode="apply",
25
+ min_approvals=2,
26
+ allowed_modes=["dry_run", "apply"],
27
+ labels=["prod", "security"],
28
+ )
29
+
30
+ request_id = result.data["request_id"]
31
+ print(f"Created: {request_id}")
32
+ # Created: 550e8400-e29b-41d4-a716-446655440000
33
+ ```
34
+
35
+ ### 2. Approve (N-of-M)
36
+
37
+ ```python
38
+ # First approval
39
+ tools.approve(
40
+ request_id=request_id,
41
+ actor=Actor(type="human", id="alice"),
42
+ comment="Reviewed plan, looks safe",
43
+ )
44
+
45
+ # Second approval - now approved
46
+ result = tools.approve(
47
+ request_id=request_id,
48
+ actor=Actor(type="human", id="bob"),
49
+ comment="LGTM",
50
+ )
51
+
52
+ print(f"Approved: {result.data['is_approved']}")
53
+ # Approved: True
54
+ ```
55
+
56
+ ### 3. Execute
57
+
58
+ ```python
59
+ # You provide the router (nexus-router instance)
60
+ from nexus_router import Router
61
+
62
+ router = Router(...) # Your router setup
63
+
64
+ result = tools.execute(
65
+ request_id=request_id,
66
+ adapter_id="subprocess:mcpt:key-rotation",
67
+ actor=Actor(type="system", id="scheduler"),
68
+ router=router,
69
+ dry_run=False,
70
+ )
71
+
72
+ print(f"Run ID: {result.data['run_id']}")
73
+ print(f"Steps: {result.data['steps_executed']}")
74
+ ```
75
+
76
+ ## Check Status
77
+
78
+ ```python
79
+ status = tools.status(request_id)
80
+
81
+ print(f"State: {status.data['state']}")
82
+ print(f"Goal: {status.data['goal']}")
83
+ print(f"Approvals: {status.data['active_approvals']}/{status.data['policy']['min_approvals']}")
84
+ print(f"Run ID: {status.data['executions'][-1]['run_id']}")
85
+ ```
86
+
87
+ ## Export Audit Record
88
+
89
+ ```python
90
+ audit = tools.export_audit_record(request_id)
91
+
92
+ # Canonical JSON for archival
93
+ with open(f"audit-{request_id}.json", "w") as f:
94
+ f.write(audit.data["canonical_json"])
95
+
96
+ # Integrity digest
97
+ print(f"Digest: {audit.data['record_digest']}")
98
+ ```
99
+
100
+ ## Policy Options
101
+
102
+ ```python
103
+ tools.request(
104
+ goal="...",
105
+ actor=Actor(type="human", id="alice"),
106
+
107
+ # Approval requirements
108
+ min_approvals=2, # Need 2 distinct approvers
109
+
110
+ # Execution constraints
111
+ mode="apply", # Requested mode
112
+ allowed_modes=["dry_run", "apply"], # What policy permits
113
+ max_steps=50, # Passed to router
114
+
115
+ # Adapter requirements
116
+ require_adapter_capabilities=["timeout", "external"],
117
+
118
+ # Governance
119
+ labels=["prod", "finance"], # For routing/filtering
120
+ )
121
+ ```
122
+
123
+ ## Dry Run First
124
+
125
+ ```python
126
+ # Execute in dry_run mode even if request was for apply
127
+ result = tools.execute(
128
+ request_id=request_id,
129
+ adapter_id="adapter",
130
+ actor=Actor(type="human", id="alice"),
131
+ router=router,
132
+ dry_run=True, # Override to dry_run
133
+ )
134
+
135
+ # Review output, then execute for real
136
+ result = tools.execute(
137
+ request_id=request_id,
138
+ adapter_id="adapter",
139
+ actor=Actor(type="human", id="alice"),
140
+ router=router,
141
+ dry_run=False,
142
+ )
143
+ ```
144
+
145
+ ## Timeline View
146
+
147
+ ```python
148
+ status = tools.status(request_id, include_events=True)
149
+
150
+ for event in status.data["events"]:
151
+ print(f"{event['ts']} | {event['event_type']} | {event['actor']['id']}")
152
+
153
+ # 2024-01-15T10:00:00Z | DECISION_CREATED | alice
154
+ # 2024-01-15T10:00:00Z | POLICY_ATTACHED | alice
155
+ # 2024-01-15T10:05:00Z | APPROVAL_GRANTED | alice
156
+ # 2024-01-15T10:10:00Z | APPROVAL_GRANTED | bob
157
+ # 2024-01-15T10:15:00Z | EXECUTION_REQUESTED | scheduler
158
+ # 2024-01-15T10:15:01Z | EXECUTION_STARTED | nexus-control
159
+ # 2024-01-15T10:15:30Z | EXECUTION_COMPLETED | nexus-control
160
+ ```
161
+
162
+ ## What Makes This Useful
163
+
164
+ 1. **Audit trail**: Every action has an actor, timestamp, and digest
165
+ 2. **N-of-M approvals**: Real approval workflows, not just flags
166
+ 3. **Policy enforcement**: Mode restrictions, capability requirements
167
+ 4. **Router integration**: Links to nexus-router run_id for full execution audit
168
+ 5. **Exportable**: Canonical JSON records for compliance/archival
169
+
170
+ That's operational power.