plexus-mesh 0.2.2__py3-none-any.whl
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.
- plexus/__init__.py +27 -0
- plexus/__main__.py +4 -0
- plexus/cli.py +139 -0
- plexus/graph.py +38 -0
- plexus/manifest.py +117 -0
- plexus/mcp.py +156 -0
- plexus/mesh.py +88 -0
- plexus/plan.py +120 -0
- plexus/receipt.py +66 -0
- plexus/registry.py +418 -0
- plexus/run.py +44 -0
- plexus_mesh-0.2.2.dist-info/METADATA +378 -0
- plexus_mesh-0.2.2.dist-info/RECORD +17 -0
- plexus_mesh-0.2.2.dist-info/WHEEL +5 -0
- plexus_mesh-0.2.2.dist-info/entry_points.txt +2 -0
- plexus_mesh-0.2.2.dist-info/licenses/LICENSE +110 -0
- plexus_mesh-0.2.2.dist-info/top_level.txt +1 -0
plexus/plan.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""plan.py — turn the mesh into an executable pipeline.
|
|
2
|
+
|
|
3
|
+
Two questions a user actually asks:
|
|
4
|
+
- "I want to feed tool X — what upstream chain produces its inputs?" -> plan_to
|
|
5
|
+
- "I have tool A's output and want tool B's verdict — how do they connect?" -> route
|
|
6
|
+
|
|
7
|
+
Both return ordered steps naming each hop's invocation (the declared CLI) plus
|
|
8
|
+
the capability that justifies it. A hop is auditable always; it is runnable only
|
|
9
|
+
when both ends declare a CLI. When one does not, the hop is marked
|
|
10
|
+
`runnable: false` and the absence is named, never coerced into a command.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from .mesh import Mesh
|
|
15
|
+
from .receipt import build_plan_receipt
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _cli(mesh: Mesh, organ: str):
|
|
19
|
+
"""The declared CLI for an organ, or None when the manifest declares none.
|
|
20
|
+
Absence is returned honestly, never laundered into the organ id."""
|
|
21
|
+
inv = mesh.manifests[organ].invoke if organ in mesh.manifests else {}
|
|
22
|
+
return inv.get("cli")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _token(cli, organ: str) -> str:
|
|
26
|
+
return cli if cli else f"{organ}(no cli declared)"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _toposort(mesh: Mesh, nodes: set) -> tuple:
|
|
30
|
+
"""Kahn's algorithm over non-self edges induced on `nodes`. Returns
|
|
31
|
+
(order, cyclic): acyclic prefix in dependency order, then any nodes left in a
|
|
32
|
+
feedback loop (reported, never silently linearized)."""
|
|
33
|
+
edges = [(e.producer, e.consumer) for e in mesh.edges
|
|
34
|
+
if not e.self_loop and e.producer in nodes and e.consumer in nodes
|
|
35
|
+
and e.producer != e.consumer]
|
|
36
|
+
indeg = {n: 0 for n in nodes}
|
|
37
|
+
for _, c in edges:
|
|
38
|
+
indeg[c] += 1
|
|
39
|
+
ready = sorted(n for n in nodes if indeg[n] == 0)
|
|
40
|
+
order = []
|
|
41
|
+
while ready:
|
|
42
|
+
n = ready.pop(0)
|
|
43
|
+
order.append(n)
|
|
44
|
+
for p, c in edges:
|
|
45
|
+
if p == n:
|
|
46
|
+
indeg[c] -= 1
|
|
47
|
+
if indeg[c] == 0:
|
|
48
|
+
ready.append(c)
|
|
49
|
+
ready.sort()
|
|
50
|
+
cyclic = sorted(n for n in nodes if n not in order)
|
|
51
|
+
return order + cyclic, cyclic
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def plan_to(mesh: Mesh, target: str) -> dict:
|
|
55
|
+
"""The upstream producers that (transitively) feed `target`, in dependency
|
|
56
|
+
order. Pure sources first; any feedback loop is reported in `cyclic` rather
|
|
57
|
+
than forced into a false linear order."""
|
|
58
|
+
if target not in mesh.manifests:
|
|
59
|
+
return {"target": target, "error": "unknown organ", "order": []}
|
|
60
|
+
|
|
61
|
+
upstream, frontier = set(), [target]
|
|
62
|
+
while frontier:
|
|
63
|
+
node = frontier.pop()
|
|
64
|
+
for producer in mesh.producers_of(node):
|
|
65
|
+
if producer != target and producer not in upstream:
|
|
66
|
+
upstream.add(producer)
|
|
67
|
+
frontier.append(producer)
|
|
68
|
+
nodes = upstream | {target}
|
|
69
|
+
|
|
70
|
+
order, cyclic = _toposort(mesh, nodes)
|
|
71
|
+
hops = []
|
|
72
|
+
for e in mesh.edges:
|
|
73
|
+
if e.self_loop or e.producer not in nodes or e.consumer not in nodes:
|
|
74
|
+
continue
|
|
75
|
+
p_cli, c_cli = _cli(mesh, e.producer), _cli(mesh, e.consumer)
|
|
76
|
+
hops.append({"producer": e.producer, "consumer": e.consumer,
|
|
77
|
+
"capability": e.capability,
|
|
78
|
+
"invoke": f"{_token(p_cli, e.producer)} -> {_token(c_cli, e.consumer)}",
|
|
79
|
+
"runnable": p_cli is not None and c_cli is not None})
|
|
80
|
+
incoming = {c for _, c in [(e.producer, e.consumer) for e in mesh.edges
|
|
81
|
+
if not e.self_loop and e.producer in nodes
|
|
82
|
+
and e.consumer in nodes and e.producer != e.consumer]}
|
|
83
|
+
plan = {"target": target, "order": order, "hops": hops, "cyclic": cyclic,
|
|
84
|
+
"sources": [n for n in order if n not in incoming]}
|
|
85
|
+
plan["receipt"] = build_plan_receipt(mesh, plan)
|
|
86
|
+
return plan
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def route(mesh: Mesh, source: str, target: str) -> dict:
|
|
90
|
+
"""Shortest capability-path from `source` to `target` (BFS over edges)."""
|
|
91
|
+
if source not in mesh.manifests or target not in mesh.manifests:
|
|
92
|
+
return {"source": source, "target": target, "error": "unknown organ", "path": []}
|
|
93
|
+
# BFS keeping the edge used to reach each node
|
|
94
|
+
prev: dict = {source: None}
|
|
95
|
+
queue = [source]
|
|
96
|
+
while queue:
|
|
97
|
+
node = queue.pop(0)
|
|
98
|
+
if node == target:
|
|
99
|
+
break
|
|
100
|
+
for e in mesh.edges:
|
|
101
|
+
if e.self_loop or e.producer != node or e.consumer in prev:
|
|
102
|
+
continue
|
|
103
|
+
prev[e.consumer] = e
|
|
104
|
+
queue.append(e.consumer)
|
|
105
|
+
if target not in prev:
|
|
106
|
+
out = {"source": source, "target": target, "path": [], "connected": False}
|
|
107
|
+
out["receipt"] = build_plan_receipt(mesh, out)
|
|
108
|
+
return out
|
|
109
|
+
chain = []
|
|
110
|
+
node = target
|
|
111
|
+
while prev[node] is not None:
|
|
112
|
+
e = prev[node]
|
|
113
|
+
chain.append({"producer": e.producer, "consumer": e.consumer,
|
|
114
|
+
"capability": e.capability})
|
|
115
|
+
node = e.producer
|
|
116
|
+
chain.reverse()
|
|
117
|
+
out = {"source": source, "target": target, "connected": True,
|
|
118
|
+
"hops": len(chain), "path": chain}
|
|
119
|
+
out["receipt"] = build_plan_receipt(mesh, out)
|
|
120
|
+
return out
|
plexus/receipt.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""receipt.py -- a re-derivable receipt for a plexus plan or route.
|
|
2
|
+
|
|
3
|
+
A plan is a claim: "given THESE manifests, this is the wiring." The receipt binds the
|
|
4
|
+
derivation to the exact manifests it came from: the content hash of every organ in the
|
|
5
|
+
plan, plus a hash over the derived body. So a stranger holding the mesh and the plan
|
|
6
|
+
re-derives it and confirms the receipt, and a manifest that changed since the plan is
|
|
7
|
+
caught -- the wiring silently shifting under you is the failure this prevents.
|
|
8
|
+
|
|
9
|
+
verify_plan re-derives the plan FROM THE MESH (never trusting the plan's stored body),
|
|
10
|
+
so a forger who tampers the body and recomputes the hash is still caught. Zero-dep.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import hashlib
|
|
15
|
+
import json
|
|
16
|
+
|
|
17
|
+
from .manifest import content_hash
|
|
18
|
+
|
|
19
|
+
SCHEMA = "plexus.plan-receipt/1"
|
|
20
|
+
METHOD_VERSION = "plexus-plan/1"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _plan_organs(plan: dict) -> set:
|
|
24
|
+
"""Every organ the plan references, so each one's manifest is bound to the receipt."""
|
|
25
|
+
organs: set = set()
|
|
26
|
+
organs.update(plan.get("order") or [])
|
|
27
|
+
for key in ("source", "target"):
|
|
28
|
+
if plan.get(key):
|
|
29
|
+
organs.add(plan[key])
|
|
30
|
+
for key in ("hops", "path"):
|
|
31
|
+
rows = plan.get(key)
|
|
32
|
+
if isinstance(rows, list): # route's `hops` is an int count, skip it; `path` is the list
|
|
33
|
+
for hop in rows:
|
|
34
|
+
if isinstance(hop, dict):
|
|
35
|
+
organs.update(x for x in (hop.get("producer"), hop.get("consumer")) if x)
|
|
36
|
+
return organs
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _plan_body_sha(plan: dict) -> str:
|
|
40
|
+
body = {k: v for k, v in plan.items() if k != "receipt"}
|
|
41
|
+
return hashlib.sha256(
|
|
42
|
+
json.dumps(body, sort_keys=True, ensure_ascii=False).encode("utf-8")).hexdigest()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def build_plan_receipt(mesh, plan: dict) -> dict:
|
|
46
|
+
"""Bind the plan to the content hash of every organ it references plus its body hash."""
|
|
47
|
+
organs = sorted(o for o in _plan_organs(plan) if o in mesh.manifests)
|
|
48
|
+
manifest_shas = {o: content_hash(mesh.manifests[o]) for o in organs}
|
|
49
|
+
return {"schema": SCHEMA, "method_version": METHOD_VERSION,
|
|
50
|
+
"manifest_shas": manifest_shas, "plan_sha256": _plan_body_sha(plan)}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def verify_plan(plan: dict, mesh) -> bool:
|
|
54
|
+
"""Re-derive the plan from the mesh and confirm its receipt. A tampered body or a
|
|
55
|
+
manifest that changed since the plan both fail. Read-only."""
|
|
56
|
+
r = plan.get("receipt")
|
|
57
|
+
if not isinstance(r, dict) or r.get("method_version") != METHOD_VERSION:
|
|
58
|
+
return False
|
|
59
|
+
from .plan import plan_to, route
|
|
60
|
+
if "source" in plan and "target" in plan:
|
|
61
|
+
fresh = route(mesh, plan["source"], plan["target"])
|
|
62
|
+
elif "target" in plan:
|
|
63
|
+
fresh = plan_to(mesh, plan["target"])
|
|
64
|
+
else:
|
|
65
|
+
return False
|
|
66
|
+
return build_plan_receipt(mesh, fresh) == r
|
plexus/registry.py
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"""registry.py — the built-in manifests, transcribed from a one-time code survey.
|
|
2
|
+
|
|
3
|
+
Each capability key and module pointer below was transcribed by hand from the
|
|
4
|
+
flagship source during public-source surveys. plexus does not re-read that source
|
|
5
|
+
at runtime, so these pointers are DECLARED citations, not probed receipts: if a
|
|
6
|
+
flagship renames a cited symbol, the manifest here goes stale silently until the
|
|
7
|
+
next manual survey. The Mneme contract was refreshed from public main on
|
|
8
|
+
2026-09-14. The Canon and Relay contracts were added from public origin/main on
|
|
9
|
+
2026-09-16. Capability keys are aligned across producers and consumers so
|
|
10
|
+
a declared edge forms where the code composed at survey time: gather.digest/1 ->
|
|
11
|
+
crucible, gather.items/1 -> mneme, mneme.crucible-export/2 (as crucible.thesis/1)
|
|
12
|
+
-> crucible, crucible.replay-template/1 -> mneme,
|
|
13
|
+
crucible.replay-pack/1 -> crucible, index.verification/1 -> crucible, and
|
|
14
|
+
project-telos.flagship-action/v1 envelopes from the organs that declare them ->
|
|
15
|
+
index's spine loader.
|
|
16
|
+
|
|
17
|
+
External manifests can be loaded from a directory of *.interop.json files with
|
|
18
|
+
the same shape (see Manifest.to_dict), so a tool ships its own contract.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
from .manifest import Manifest
|
|
26
|
+
|
|
27
|
+
FLAGSHIP = "project-telos.flagship-action/v1"
|
|
28
|
+
|
|
29
|
+
_SEED = [
|
|
30
|
+
{
|
|
31
|
+
"organ": "gather",
|
|
32
|
+
"invoke": {"cli": "gather", "mcp_server": "gather.mcp:serve", "python_import": "gather"},
|
|
33
|
+
"emits": [
|
|
34
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
35
|
+
"module": "src/gather/flagship.py:envelope"},
|
|
36
|
+
{"capability": "gather.digest/1", "title": "witnessed digest seal",
|
|
37
|
+
"module": "src/gather/digest.py:Digest.to_json"},
|
|
38
|
+
{"capability": "gather.items/1", "title": "per-item provenance receipts",
|
|
39
|
+
"module": "src/gather/digest.py:_receipt"},
|
|
40
|
+
{"capability": "gather.catalog-digest/1", "title": "docs/arxiv catalog + digest",
|
|
41
|
+
"module": "src/gather/payloads.py:catalog_digest_payload"},
|
|
42
|
+
],
|
|
43
|
+
"consumes": [
|
|
44
|
+
{"capability": "provenance.verdict/1", "title": "external provenance verdict",
|
|
45
|
+
"module": "src/gather/provenance.py:SubprocessProvenanceProvider.origin"},
|
|
46
|
+
{"capability": "gather.run-config/1", "title": "multi-source run config",
|
|
47
|
+
"module": "src/gather/run_config.py:load_run_config"},
|
|
48
|
+
],
|
|
49
|
+
"evidence": ["src/gather/interop.py", "src/gather/digest.py",
|
|
50
|
+
"src/gather/payloads.py", "src/gather/flagship.py"],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"organ": "crucible",
|
|
54
|
+
"invoke": {"cli": "crucible", "mcp_server": "crucible.mcp:serve", "python_import": "crucible"},
|
|
55
|
+
"emits": [
|
|
56
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
57
|
+
"module": "src/crucible/flagship.py:envelope"},
|
|
58
|
+
{"capability": "crucible.assessment/1", "title": "witnessed assessment",
|
|
59
|
+
"module": "src/crucible/assess.py:Assessment.to_dict"},
|
|
60
|
+
{"capability": "project-telos.crucible.measurement-gate/v1", "title": "measurement gate",
|
|
61
|
+
"module": "src/crucible/measurement_gate.py:_result"},
|
|
62
|
+
{"capability": "crucible.thesis-export/1", "title": "public thesis contract",
|
|
63
|
+
"module": "src/crucible/gate.py:export_thesis"},
|
|
64
|
+
{"capability": "crucible.replay-template/1", "title": "oracle replay template",
|
|
65
|
+
"module": "src/crucible/recheck_cmd.py:_write_template"},
|
|
66
|
+
],
|
|
67
|
+
"consumes": [
|
|
68
|
+
{"capability": "crucible.thesis/1", "title": "thesis JSON",
|
|
69
|
+
"module": "src/crucible/commands.py:_thesis_from_data"},
|
|
70
|
+
{"capability": "crucible.measurements/1", "title": "per-claim measurements",
|
|
71
|
+
"module": "src/crucible/commands.py:_load_measurements"},
|
|
72
|
+
{"capability": "crucible.replay-pack/1", "title": "assessment-bound replay pack",
|
|
73
|
+
"module": "src/crucible/recheck_cmd.py:_load_replay_pack"},
|
|
74
|
+
{"capability": "gather.digest/1", "title": "gather digest as evidence",
|
|
75
|
+
"module": "src/crucible/ecosystem_measure.py:GatherDigestMeasure"},
|
|
76
|
+
{"capability": "index.verification/1", "title": "index structural verdict",
|
|
77
|
+
"module": "src/crucible/ecosystem_measure.py:verify_index_verification"},
|
|
78
|
+
],
|
|
79
|
+
"evidence": ["src/crucible/ecosystem_measure.py", "src/crucible/commands.py",
|
|
80
|
+
"src/crucible/assess.py", "src/crucible/gate.py",
|
|
81
|
+
"src/crucible/recheck_cmd.py"],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"organ": "forum",
|
|
85
|
+
"invoke": {"cli": "forum", "mcp_server": "forum.mcp_surface:serve_stdio", "python_import": "forum"},
|
|
86
|
+
"emits": [
|
|
87
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
88
|
+
"module": "src/forum/flagship.py:envelope"},
|
|
89
|
+
{"capability": "forum.flight-recorder/1", "title": "trace -> verifiable ledger",
|
|
90
|
+
"module": "src/forum/flight_recorder.py:import_trace"},
|
|
91
|
+
{"capability": "project-telos.action-receipt/v1", "title": "submit action receipt",
|
|
92
|
+
"module": "src/forum/receipts.py:submit_receipt"},
|
|
93
|
+
{"capability": "forum.context-capsule/v1", "title": "witnessed context capsule",
|
|
94
|
+
"module": "src/forum/context_capsule.py:build_context_capsule"},
|
|
95
|
+
],
|
|
96
|
+
"consumes": [
|
|
97
|
+
{"capability": "external-agent-trace/1", "title": "LangSmith/OTel/AgentOps trace",
|
|
98
|
+
"module": "src/forum/flight_recorder.py:normalize_trace"},
|
|
99
|
+
],
|
|
100
|
+
"evidence": ["src/forum/ledger.py", "src/forum/flight_recorder.py",
|
|
101
|
+
"src/forum/flagship.py", "src/forum/receipts.py"],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"organ": "index",
|
|
105
|
+
"invoke": {"cli": "index", "mcp_server": "index_graph.mcp:serve", "python_import": "index_graph"},
|
|
106
|
+
"emits": [
|
|
107
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
108
|
+
"module": "src/index_graph/flagship.py:envelope"},
|
|
109
|
+
{"capability": "project-telos.context-envelope/v1", "title": "budgeted context envelope",
|
|
110
|
+
"module": "src/index_graph/context/envelope.py:build_context_envelope"},
|
|
111
|
+
{"capability": "index.verification/1", "title": "structural-claim verdict",
|
|
112
|
+
"module": "src/index_graph/verify.py:build_verification"},
|
|
113
|
+
{"capability": "index.invalidation-pin/1", "title": "freshness pin",
|
|
114
|
+
"module": "src/index_graph/freshness/invalidate.py:mint_pin"},
|
|
115
|
+
{"capability": "index.wiki/1", "title": "sealed commit-pinned wiki",
|
|
116
|
+
"module": "src/index_graph/wiki/pack.py:build_wiki_pack"},
|
|
117
|
+
],
|
|
118
|
+
"consumes": [
|
|
119
|
+
{"capability": FLAGSHIP, "title": "peer envelopes into the operator spine",
|
|
120
|
+
"module": "src/index_graph/workbench.py:load_spine"},
|
|
121
|
+
{"capability": "index.invalidation-pin/1", "title": "pin to diff against the tree",
|
|
122
|
+
"module": "src/index_graph/freshness/invalidate.py:invalidation_report"},
|
|
123
|
+
{"capability": "index.wiki/1", "title": "sealed wiki to re-verify",
|
|
124
|
+
"module": "src/index_graph/wiki/seal.py:verify_wiki"},
|
|
125
|
+
],
|
|
126
|
+
"evidence": ["src/index_graph/flagship.py", "src/index_graph/context/envelope.py",
|
|
127
|
+
"src/index_graph/verify.py", "src/index_graph/workbench.py"],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"organ": "mneme",
|
|
131
|
+
"invoke": {"cli": "mneme", "mcp_server": "mneme.mcp:serve", "python_import": "mneme"},
|
|
132
|
+
"emits": [
|
|
133
|
+
{"capability": "mneme.crucible-export/2", "title": "memory as crucible thesis",
|
|
134
|
+
"module": "src/mneme/compose.py:to_crucible_thesis",
|
|
135
|
+
"summary": "claims, drift measurements, and declarative mneme.recheck/1 descriptors",
|
|
136
|
+
"consumable_as": ["crucible.thesis/1"]},
|
|
137
|
+
{"capability": "crucible.replay-pack/1", "title": "assessment-bound Mneme drift replay",
|
|
138
|
+
"module": "src/mneme/replay.py:replay_crucible",
|
|
139
|
+
"summary": "replays descriptor-bound measurements without importing Crucible or executing commands"},
|
|
140
|
+
{"capability": "mneme.local-origin-recheck/1", "title": "supported local origin freshness report",
|
|
141
|
+
"module": "src/mneme/origin.py:recheck_local_origins",
|
|
142
|
+
"summary": "explicit read-only local docs/file-read freshness checks under a caller-approved root"},
|
|
143
|
+
{"capability": "mneme.provenance-chain/1", "title": "memory -> source origin",
|
|
144
|
+
"module": "src/mneme/ingest.py:provenance_chain",
|
|
145
|
+
"summary": "memory-to-origin receipt chain; external freshness is checked separately when supported"},
|
|
146
|
+
{"capability": "mneme.recall/1", "title": "re-derivable recall receipt",
|
|
147
|
+
"module": "src/mneme/receipt.py:RecallReceipt.as_dict"},
|
|
148
|
+
{"capability": "mneme.drift-report/1", "title": "memory faithfulness verdicts",
|
|
149
|
+
"module": "src/mneme/drift.py:drift_report"},
|
|
150
|
+
],
|
|
151
|
+
"consumes": [
|
|
152
|
+
{"capability": "gather.items/1", "title": "accountable intake items",
|
|
153
|
+
"module": "src/mneme/ingest.py:from_gather"},
|
|
154
|
+
{"capability": "conversation-turns/1", "title": "raw turns to remember",
|
|
155
|
+
"module": "src/mneme/memory.py:AgentMemory.remember"},
|
|
156
|
+
{"capability": "crucible.replay-template/1", "title": "assessment-bound measurement replay template",
|
|
157
|
+
"module": "src/mneme/replay.py:replay_crucible",
|
|
158
|
+
"summary": "decoded Crucible template plus an explicitly supplied Mneme state"},
|
|
159
|
+
],
|
|
160
|
+
"evidence": ["src/mneme/compose.py", "src/mneme/ingest.py",
|
|
161
|
+
"src/mneme/origin.py", "src/mneme/receipt.py",
|
|
162
|
+
"src/mneme/drift.py", "src/mneme/replay.py",
|
|
163
|
+
"tests/test_crucible_replay.py"],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"organ": "canon",
|
|
167
|
+
"invoke": {"cli": "canon", "mcp_server": "canon.local_mcp:serve", "python_import": "canon"},
|
|
168
|
+
"emits": [
|
|
169
|
+
{"capability": "canon.record/v1", "title": "provider-neutral context record",
|
|
170
|
+
"module": "src/canon/schema.py:Record.to_dict",
|
|
171
|
+
"summary": "one typed envelope for personality blocks, memories, personas, decisions, and research references"},
|
|
172
|
+
{"capability": "canon.capsule/v1", "title": "continuity capsule",
|
|
173
|
+
"module": "src/canon/capsule_build.py:compile_capsule",
|
|
174
|
+
"summary": "explicit records.jsonl and atoms.jsonl compile into capsule JSON, Canon Markdown, and readiness artifacts"},
|
|
175
|
+
{"capability": "canon.readiness-probe/1", "title": "capsule readiness probe",
|
|
176
|
+
"module": "src/canon/readiness.py:ReadinessProbe.to_dict",
|
|
177
|
+
"summary": "target acknowledgement challenge bound to one compiled capsule"},
|
|
178
|
+
{"capability": "canon.bootstrap-witness/1", "title": "context bootstrap witness",
|
|
179
|
+
"module": "src/canon/witness.py:BootstrapWitness.to_dict",
|
|
180
|
+
"summary": "records source state, capsule identity, readiness outcome, and does-not-prove limits"},
|
|
181
|
+
{"capability": "canon.local-mcp-readonly/1", "title": "read-only Canon MCP surface",
|
|
182
|
+
"module": "src/canon/local_mcp.py:TOOLS",
|
|
183
|
+
"summary": "status, doctor, blocks, render, validate, and check; this server writes no files"},
|
|
184
|
+
],
|
|
185
|
+
"consumes": [
|
|
186
|
+
{"capability": "canon.record/v1", "title": "validated records from explicit source files",
|
|
187
|
+
"module": "src/canon/bootstrap_runtime_inputs.py:_records_from_source",
|
|
188
|
+
"summary": "JSONL records are parsed and validated before capsule compile or bootstrap"},
|
|
189
|
+
{"capability": "canon.atom/v1", "title": "validated bootstrap atoms from explicit source files",
|
|
190
|
+
"module": "src/canon/bootstrap_runtime_inputs.py:_atoms_from_source",
|
|
191
|
+
"summary": "JSONL atoms are parsed and validated before capsule compile or bootstrap"},
|
|
192
|
+
{"capability": "canon.readiness-response/1", "title": "host readiness response",
|
|
193
|
+
"module": "src/canon/readiness.py:evaluate_readiness_response",
|
|
194
|
+
"summary": "an optional host response is evaluated against the probe; absent response is reported as unknown"},
|
|
195
|
+
{"capability": "canon.capsule/v1", "title": "capsule Markdown carrier verification",
|
|
196
|
+
"module": "src/canon/canonmd.py:verify_canon_md",
|
|
197
|
+
"summary": "re-renders the embedded carrier capsule and reports drift or mismatch"},
|
|
198
|
+
],
|
|
199
|
+
"evidence": ["README.md", "pyproject.toml", "src/canon/schema.py",
|
|
200
|
+
"src/canon/local_mcp.py", "src/canon/capsule_build.py",
|
|
201
|
+
"src/canon/bootstrap_runtime_inputs.py", "src/canon/readiness.py",
|
|
202
|
+
"src/canon/witness.py", "src/canon/canonmd.py"],
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"organ": "relay",
|
|
206
|
+
"invoke": {"cli": "relay", "mcp_server": "relay.local_mcp:serve", "python_import": "relay"},
|
|
207
|
+
"emits": [
|
|
208
|
+
{"capability": "relay.endpoint-ladder/1", "title": "local and online endpoint ladder",
|
|
209
|
+
"module": "src/relay/endpoints.py:build_endpoints",
|
|
210
|
+
"summary": "configured provider/API/gateway/cloud rungs are built only from caller-supplied environment"},
|
|
211
|
+
{"capability": "relay.agent-run-result/1", "title": "gated agent run result",
|
|
212
|
+
"module": "src/relay/local_loop.py:run_agent",
|
|
213
|
+
"summary": "final answer, checkpoint, verification fields, acceptance check, reviewability, and observed route"},
|
|
214
|
+
{"capability": "relay.session-ledger/1", "title": "hash-chained session ledger",
|
|
215
|
+
"module": "src/relay/local_session.py:SessionLedger.to_jsonl",
|
|
216
|
+
"summary": "append-only run/session trajectory that re-verifies on load"},
|
|
217
|
+
{"capability": "relay.rvc/v1", "title": "Relay-Verified-Correctness certificate",
|
|
218
|
+
"module": "src/relay/cert.py:emit_cert",
|
|
219
|
+
"summary": "self-contained certificate embedding a witnessed ledger and typed acceptance contract"},
|
|
220
|
+
{"capability": "relay.remote-mcp/1", "title": "remote MCP endpoint",
|
|
221
|
+
"module": "src/relay/remote_mcp.py:process",
|
|
222
|
+
"summary": "Streamable HTTP MCP endpoint with bearer/OAuth authorization and remote exec forced off unless opted in"},
|
|
223
|
+
],
|
|
224
|
+
"consumes": [
|
|
225
|
+
{"capability": "relay.mcp-run-request/v1", "title": "bounded MCP run request",
|
|
226
|
+
"module": "src/relay/local_mcp.py:_request_binding",
|
|
227
|
+
"summary": "binds goal, root, backend/model hints, write/exec gates, checks, and compaction budget"},
|
|
228
|
+
{"capability": "relay.rvc/v1", "title": "offline certificate verification",
|
|
229
|
+
"module": "src/relay/cert.py:verify_cert",
|
|
230
|
+
"summary": "re-derives ALLOW, UNVERIFIABLE, or REFUTED from the embedded ledger and contract"},
|
|
231
|
+
{"capability": "relay.session-ledger/1", "title": "saved session listing and reopening",
|
|
232
|
+
"module": "src/relay/session_store.py:get_session",
|
|
233
|
+
"summary": "saved ledgers are listed, reloaded, and re-verified from RELAY_SESSION_DIR"},
|
|
234
|
+
],
|
|
235
|
+
"evidence": ["README.md", "pyproject.toml", "src/relay/endpoints.py",
|
|
236
|
+
"src/relay/local_mcp.py", "src/relay/local_loop.py",
|
|
237
|
+
"src/relay/local_session.py", "src/relay/session_store.py",
|
|
238
|
+
"src/relay/cert.py", "src/relay/remote_mcp.py"],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"organ": "learn",
|
|
242
|
+
"invoke": {"cli": "learn", "mcp_server": "src/mcp.mjs", "node_entry": "src/mcp.mjs"},
|
|
243
|
+
"emits": [
|
|
244
|
+
{"capability": "learn-receipt", "title": "tutor credential/mastery ledger entries",
|
|
245
|
+
"module": "src/interop.mjs:receiptEntry"},
|
|
246
|
+
{"capability": "learn.tutor-mastery/1", "title": "mastery gate verdict",
|
|
247
|
+
"module": "src/tutor/tutor.mjs:mastery"},
|
|
248
|
+
{"capability": "learn.tutor-prooflesson/1", "title": "proof packet to lesson scaffold",
|
|
249
|
+
"module": "src/tutor/prooflesson.mjs:proofLesson"},
|
|
250
|
+
{"capability": "learn.tutor-misconceptions/1", "title": "ranked misconception aggregation",
|
|
251
|
+
"module": "src/tutor/misconception.mjs:misconceptions"},
|
|
252
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
253
|
+
"module": "src/interop.mjs:receiptEntry"},
|
|
254
|
+
],
|
|
255
|
+
"consumes": [
|
|
256
|
+
{"capability": "crucible.thesis/1", "title": "crucible thesis for proof lesson",
|
|
257
|
+
"module": "src/tutor/prooflesson.mjs:proofLesson"},
|
|
258
|
+
],
|
|
259
|
+
"evidence": ["src/interop.mjs", "src/tutor/tutor.mjs",
|
|
260
|
+
"src/tutor/prooflesson.mjs", "src/tutor/misconception.mjs"],
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"organ": "telos",
|
|
264
|
+
"invoke": {"cli": "telos", "mcp_server": "demo/telos-mcp.mjs", "node_entry": "demo/telos-mcp.mjs"},
|
|
265
|
+
"emits": [
|
|
266
|
+
{"capability": "telos.room/1", "title": "five-flagship room summary",
|
|
267
|
+
"module": "src/telos-mcp.mjs:telos_room"},
|
|
268
|
+
{"capability": "telos.workflow/1", "title": "golden workflow verification",
|
|
269
|
+
"module": "src/telos-mcp.mjs:telos_workflow"},
|
|
270
|
+
{"capability": "telos.status/1", "title": "workbench readiness + next actions",
|
|
271
|
+
"module": "src/telos-mcp.mjs:telos_status"},
|
|
272
|
+
{"capability": FLAGSHIP, "title": "flagship-action envelope",
|
|
273
|
+
"module": "src/telos-mcp.mjs:telos_status"},
|
|
274
|
+
],
|
|
275
|
+
"consumes": [
|
|
276
|
+
{"capability": "project-telos.flagship-action/v1", "title": "cross-tool action",
|
|
277
|
+
"module": "src/telos-mcp.mjs:telos_room"},
|
|
278
|
+
],
|
|
279
|
+
"evidence": ["demo/telos-mcp.mjs"],
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"organ": "flywheel-infra",
|
|
283
|
+
"invoke": {"cli": "flywheel", "python_import": "harness"},
|
|
284
|
+
"emits": [
|
|
285
|
+
{"capability": "flywheel.egress/1", "title": "sealed egress event receipt",
|
|
286
|
+
"module": "harness/infra/egress.py:build_egress_receipt"},
|
|
287
|
+
{"capability": "flywheel.lesson/1", "title": "sealed organizational lesson",
|
|
288
|
+
"module": "harness/lesson.py:build_lesson"},
|
|
289
|
+
{"capability": "flywheel.tool-call-receipt/1", "title": "sealed tool-call receipt",
|
|
290
|
+
"module": "harness/tool_call_receipt.py:build_receipt"},
|
|
291
|
+
{"capability": "flywheel.tadr-classification/1", "title": "sealed tier classification",
|
|
292
|
+
"module": "harness/governance/tadr_receipt.py:build_classification_receipt"},
|
|
293
|
+
{"capability": "flywheel.governance-envelope/1", "title": "cross-lane governance state",
|
|
294
|
+
"module": "harness/governance_envelope.py:GovernanceEnvelope"},
|
|
295
|
+
{"capability": "flywheel.credential-scan/1", "title": "sealed credential exposure report",
|
|
296
|
+
"module": "harness/infra/credential_scanner.py:build_credential_scan_receipt"},
|
|
297
|
+
{"capability": "flywheel.correlated-event/1", "title": "cross-layer correlated detection",
|
|
298
|
+
"module": "harness/infra/correlator.py:build_correlated_receipt"},
|
|
299
|
+
{"capability": "flywheel.isolation-test/1", "title": "boundary test verdict",
|
|
300
|
+
"module": "harness/infra/isolation_test.py:run_isolation_test"},
|
|
301
|
+
{"capability": "flywheel.kill-switch/1", "title": "dual-confirmed infrastructure stop",
|
|
302
|
+
"module": "harness/infra/kill_switch.py:build_kill_receipt"},
|
|
303
|
+
{"capability": "flywheel.run-bom/1", "title": "sealed run bill of materials",
|
|
304
|
+
"module": "harness/infra/run_bom.py:RunBOM.sealed"},
|
|
305
|
+
],
|
|
306
|
+
"consumes": [
|
|
307
|
+
{"capability": "accountable-surface.actuation-outcome/1",
|
|
308
|
+
"title": "intent-vs-outcome for lesson derivation",
|
|
309
|
+
"module": "harness/lesson_mappers.py:intent_outcome_lessons"},
|
|
310
|
+
{"capability": "mneme.drift-report/1",
|
|
311
|
+
"title": "memory drift for lesson derivation",
|
|
312
|
+
"module": "harness/lesson_mappers.py:drift_lessons"},
|
|
313
|
+
{"capability": "learn.tutor-misconceptions/1",
|
|
314
|
+
"title": "graded failures for lesson derivation",
|
|
315
|
+
"module": "harness/lesson_mappers.py:misconception_lessons"},
|
|
316
|
+
],
|
|
317
|
+
"evidence": ["harness/lesson.py", "harness/infra/egress.py",
|
|
318
|
+
"harness/governance/tadr_receipt.py",
|
|
319
|
+
"harness/tool_call_receipt.py"],
|
|
320
|
+
},
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def builtin_manifests() -> list:
|
|
325
|
+
"""The built-in flagship manifests, tagged with their in-code source.
|
|
326
|
+
|
|
327
|
+
Covers: gather, crucible, index, forum, mneme, canon, relay, learn, telos,
|
|
328
|
+
flywheel-infra.
|
|
329
|
+
"""
|
|
330
|
+
out = []
|
|
331
|
+
for d in _SEED:
|
|
332
|
+
m = Manifest.from_dict(d)
|
|
333
|
+
m.source = "builtin:registry"
|
|
334
|
+
out.append(m)
|
|
335
|
+
return out
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def probe_lane(name: str, timeout: float = 10.0) -> dict:
|
|
339
|
+
"""Probe a lane by spawning its MCP server and calling status/doctor.
|
|
340
|
+
|
|
341
|
+
Unlike the declared manifest (which cites source files without running
|
|
342
|
+
them), this actually spawns the lane and verifies it responds. Returns
|
|
343
|
+
{name, reachable, tools, error}.
|
|
344
|
+
|
|
345
|
+
Requires the lane's MCP server to be installed and on PATH.
|
|
346
|
+
"""
|
|
347
|
+
result = {"name": name, "reachable": False, "tools": [], "error": ""}
|
|
348
|
+
try:
|
|
349
|
+
from harness.lanes import resolve_mcp_command, LANES
|
|
350
|
+
if name not in LANES:
|
|
351
|
+
result["error"] = f"unknown lane: {name}"
|
|
352
|
+
return result
|
|
353
|
+
command = resolve_mcp_command(name)
|
|
354
|
+
except ImportError:
|
|
355
|
+
result["error"] = "harness.lanes not available (run from flywheel)"
|
|
356
|
+
return result
|
|
357
|
+
except Exception as e:
|
|
358
|
+
result["error"] = f"resolve failed: {e}"
|
|
359
|
+
return result
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
with MCPClient(command, timeout=timeout,
|
|
363
|
+
client_name=f"plexus-probe-{name}") as c:
|
|
364
|
+
c.start()
|
|
365
|
+
tools_res = c.call_text("tools/list", {})
|
|
366
|
+
if tools_res["ok"]:
|
|
367
|
+
import json as _json
|
|
368
|
+
try:
|
|
369
|
+
data = _json.loads(tools_res["text"])
|
|
370
|
+
if isinstance(data, list):
|
|
371
|
+
result["tools"] = data
|
|
372
|
+
elif isinstance(data, dict) and "tools" in data:
|
|
373
|
+
result["tools"] = data["tools"]
|
|
374
|
+
except _json.JSONDecodeError:
|
|
375
|
+
pass
|
|
376
|
+
status_res = c.call_text("status", {})
|
|
377
|
+
result["reachable"] = status_res["ok"]
|
|
378
|
+
except Exception as e:
|
|
379
|
+
result["error"] = f"{type(e).__name__}: {e}"
|
|
380
|
+
return result
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def probe_all(timeout: float = 10.0) -> list[dict]:
|
|
384
|
+
"""Probe all built-in lanes. Returns a list of probe results."""
|
|
385
|
+
try:
|
|
386
|
+
from harness.lanes import LANES
|
|
387
|
+
names = sorted(LANES.keys())
|
|
388
|
+
except ImportError:
|
|
389
|
+
names = [m.organ for m in builtin_manifests()]
|
|
390
|
+
return [probe_lane(name, timeout=timeout) for name in names]
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def load_dir(path: str) -> list:
|
|
394
|
+
"""Load every *.interop.json manifest in a directory (external tools). Each
|
|
395
|
+
manifest records the file it was read from as its provenance source."""
|
|
396
|
+
out = []
|
|
397
|
+
for name in sorted(os.listdir(path)):
|
|
398
|
+
if name.endswith(".interop.json"):
|
|
399
|
+
full = os.path.join(path, name)
|
|
400
|
+
with open(full, encoding="utf-8") as f:
|
|
401
|
+
m = Manifest.from_dict(json.load(f))
|
|
402
|
+
m.source = full
|
|
403
|
+
out.append(m)
|
|
404
|
+
return out
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def export_all(out_dir: str) -> list:
|
|
408
|
+
"""Write each built-in manifest as <organ>.interop.json — the exact file a
|
|
409
|
+
flagship would ship to join the mesh. Returns the paths written."""
|
|
410
|
+
os.makedirs(out_dir, exist_ok=True)
|
|
411
|
+
written = []
|
|
412
|
+
for m in builtin_manifests():
|
|
413
|
+
p = os.path.join(out_dir, f"{m.organ}.interop.json")
|
|
414
|
+
with open(p, "w", encoding="utf-8") as f:
|
|
415
|
+
json.dump(m.to_dict(), f, indent=2, ensure_ascii=False)
|
|
416
|
+
f.write("\n")
|
|
417
|
+
written.append(p)
|
|
418
|
+
return written
|
plexus/run.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""run.py — turn a plan into runnable output.
|
|
2
|
+
|
|
3
|
+
`plan_to` says what feeds a target; this emits the concrete, ordered invocation
|
|
4
|
+
sequence to actually produce it — a shell script you can read, edit, and run. It
|
|
5
|
+
does NOT execute anything itself (the tools live in their own environments); it
|
|
6
|
+
makes the plan actionable and auditable instead of leaving it as advice. Feedback
|
|
7
|
+
loops are emitted as a labelled comment, never silently linearized into a lie.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from .mesh import Mesh
|
|
12
|
+
from .plan import _cli, plan_to
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def pipeline_script(mesh: Mesh, target: str) -> str:
|
|
16
|
+
"""A runnable, commented shell script that invokes each upstream tool in
|
|
17
|
+
dependency order to feed `target`."""
|
|
18
|
+
plan = plan_to(mesh, target)
|
|
19
|
+
if plan.get("error"):
|
|
20
|
+
return f"# error: {plan['error']} ({target!r})"
|
|
21
|
+
|
|
22
|
+
lines = ["#!/usr/bin/env bash", "set -euo pipefail",
|
|
23
|
+
f"# plexus pipeline to feed: {target}",
|
|
24
|
+
f"# sources: {', '.join(plan['sources']) or '(none)'}"]
|
|
25
|
+
if plan["cyclic"]:
|
|
26
|
+
lines.append(f"# NOTE: feedback loop {' <-> '.join(plan['cyclic'])} : "
|
|
27
|
+
"these tools mutually depend; run order among them is not linear")
|
|
28
|
+
lines.append("")
|
|
29
|
+
|
|
30
|
+
for organ in plan["order"]:
|
|
31
|
+
if organ == target:
|
|
32
|
+
continue
|
|
33
|
+
inbound = [h for h in plan["hops"] if h["consumer"] == organ]
|
|
34
|
+
produced = sorted({h["capability"] for h in plan["hops"] if h["producer"] == organ})
|
|
35
|
+
note = f"produces: {', '.join(produced)}" if produced else "source"
|
|
36
|
+
lines.append(f"# {organ}: {note}")
|
|
37
|
+
lines.append(f"{_cli(mesh, organ)} run # -> feeds "
|
|
38
|
+
f"{', '.join(sorted({h['consumer'] for h in plan['hops'] if h['producer'] == organ}))}")
|
|
39
|
+
lines.append("")
|
|
40
|
+
|
|
41
|
+
feeders = sorted({h["producer"] for h in plan["hops"] if h["consumer"] == target})
|
|
42
|
+
lines.append(f"# {target}: consumes from {', '.join(feeders) or '(external inputs only)'}")
|
|
43
|
+
lines.append(f"{_cli(mesh, target)} run")
|
|
44
|
+
return "\n".join(lines)
|