@passioncode-ai/passioncode 0.1.34 → 0.1.36
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/CHANGELOG.md +20 -0
- package/family.json +1 -1
- package/package.json +1 -1
- package/payload/.claude-plugin/marketplace.json +2 -2
- package/payload/manifest.json +8 -8
- package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -3
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +4 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_provider.py +5 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +6 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +98 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +8 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +492 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +865 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +47 -12
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.36 - 2026-10-12
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Fabric Agent Adapter is pinned at `v0.12.0`** (it was `v0.11.1`). The kit follows Fabric Agent Contract up to
|
|
8
|
+
DEC-0045. The delegation verifiers are sealed as the contract specifies: the trusted issuer is required, a
|
|
9
|
+
small-order key is refused as the issuer's fault, and claims are typed strictly. The operator's own machines need no
|
|
10
|
+
token (trust tiers). The canonical JSON vectors are shared with the contract, and a provider entry may say where its
|
|
11
|
+
stdio server starts (never once per session). The contract pin is `2eb91c0`.
|
|
12
|
+
|
|
13
|
+
## 0.1.35 - 2026-10-12
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Fabric Agent Adapter is pinned at `v0.11.1`** (it was `v0.10.0`). A service built with the kit can now check a
|
|
18
|
+
delegation token and an operator's approval offline, in Python and Node, with the same answers as the Fabric Agent
|
|
19
|
+
Contract's own verifier (DEC-0039). It can put a gate in front of its MCP tools, so each call names the person it
|
|
20
|
+
is for, the calling agent and the chain, and an approval is used once. The Node kit refuses small-order Ed25519
|
|
21
|
+
keys itself (Node 20 and 22 accepted a forged signature under one). The contract pin is unchanged at `8e49fbd`.
|
|
22
|
+
|
|
3
23
|
## 0.1.34 - 2026-10-11
|
|
4
24
|
|
|
5
25
|
### Changed
|
package/family.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/passioncode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "The PassionCode.ai agent skill set \u2014 Fabric Agent Adapter, Observatory Log and the organisation's working rules \u2014 for Claude Code and every other agent on the machine, updated as one set.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"passioncode": "bin/passioncode.js"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"name": "fabric-agent-adapter",
|
|
12
12
|
"displayName": "Fabric Agent Adapter",
|
|
13
13
|
"source": "./plugins/fabric-agent-adapter",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.12.0",
|
|
15
15
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles.",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "PassionCode.ai",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"name": "passioncode",
|
|
36
36
|
"displayName": "PassionCode.ai",
|
|
37
37
|
"source": "./plugins/passioncode",
|
|
38
|
-
"version": "0.1.
|
|
38
|
+
"version": "0.1.36",
|
|
39
39
|
"description": "The organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
|
|
40
40
|
"author": {
|
|
41
41
|
"name": "PassionCode.ai",
|
package/payload/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"family": "passioncode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"release": true,
|
|
5
5
|
"members": [
|
|
6
6
|
{
|
|
7
7
|
"name": "fabric-agent-adapter",
|
|
8
8
|
"displayName": "Fabric Agent Adapter",
|
|
9
9
|
"repo": "passioncode-ai/fabric-agent-adapter",
|
|
10
|
-
"ref": "v0.
|
|
11
|
-
"commit": "
|
|
12
|
-
"version": "0.
|
|
10
|
+
"ref": "v0.12.0",
|
|
11
|
+
"commit": "6f07268b0008c53ffa07132c2cde9fde31ad24ad",
|
|
12
|
+
"version": "0.12.0",
|
|
13
13
|
"via": "clone of https://***@github.com/passioncode-ai/fabric-agent-adapter.git",
|
|
14
14
|
"skills": [
|
|
15
15
|
"adapting-projects-to-fabric",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"legacyMarketplaces": [
|
|
23
23
|
"fabric-agent-adapter"
|
|
24
24
|
],
|
|
25
|
-
"contentHash": "sha256:
|
|
25
|
+
"contentHash": "sha256:426674360744d0c59e5f51341a46ddf1fad97fea9914050e8804141c1c931637",
|
|
26
26
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles.",
|
|
27
27
|
"author": {
|
|
28
28
|
"name": "PassionCode.ai",
|
|
@@ -61,16 +61,16 @@
|
|
|
61
61
|
"name": "passioncode",
|
|
62
62
|
"displayName": "PassionCode.ai",
|
|
63
63
|
"repo": "passioncode-ai/passioncode",
|
|
64
|
-
"ref": "v0.1.
|
|
64
|
+
"ref": "v0.1.36",
|
|
65
65
|
"commit": null,
|
|
66
|
-
"version": "0.1.
|
|
66
|
+
"version": "0.1.36",
|
|
67
67
|
"via": "this repository",
|
|
68
68
|
"skills": [
|
|
69
69
|
"working-in-passioncode"
|
|
70
70
|
],
|
|
71
71
|
"legacyPluginIds": [],
|
|
72
72
|
"legacyMarketplaces": [],
|
|
73
|
-
"contentHash": "sha256:
|
|
73
|
+
"contentHash": "sha256:9064a45fd8f155d8808bce22aa2ca225838ee85332a0b660d6b4ce3e516949fc",
|
|
74
74
|
"description": "The organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
|
|
75
75
|
"author": {
|
|
76
76
|
"name": "PassionCode.ai",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "fabric-agent-adapter",
|
|
4
4
|
"displayName": "Fabric Agent Adapter",
|
|
5
5
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles.",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.12.0",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -5,9 +5,9 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
5
5
|
compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode.
|
|
6
6
|
metadata:
|
|
7
7
|
author: PassionCode.ai
|
|
8
|
-
version: "0.
|
|
8
|
+
version: "0.12.0"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "2eb91c00e852d9c31d804310d38fad91589fcbac"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Adapting projects to Fabric
|
|
@@ -70,7 +70,7 @@ Use exactly:
|
|
|
70
70
|
|
|
71
71
|
- contract version `0.1.0`;
|
|
72
72
|
- repository `https://github.com/passioncode-ai/fabric-agent-contract`;
|
|
73
|
-
- commit `
|
|
73
|
+
- commit `2eb91c00e852d9c31d804310d38fad91589fcbac`.
|
|
74
74
|
|
|
75
75
|
This is the default for new bundles. When checking an issued legacy bundle, preserve its
|
|
76
76
|
explicit supported lock and use that exact clean checkout. Never silently upgrade or
|
|
@@ -32,7 +32,10 @@ python3 scripts/fabric_provider.py validate ~/Library/Application\ Support/ai.pa
|
|
|
32
32
|
python3 scripts/fabric_provider.py remove example-agent # the uninstaller
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
`--stdio` takes the rest of the line as the argument array; there is no shell string.
|
|
35
|
+
`--stdio` takes the rest of the line as the argument array; there is no shell string. An entry may carry
|
|
36
|
+
`run.mcp.stdio.scope` (DEC-0044): `project` (started for the sessions of a project that binds it) or `on-demand`;
|
|
37
|
+
`session` — a server in every coding session — is refused (FAC-SEM-056, LC-19). The validator accepts the field; the
|
|
38
|
+
writer does not set it until Fabric reads it.
|
|
36
39
|
|
|
37
40
|
It refuses, with one sentence that never quotes a value:
|
|
38
41
|
|
|
@@ -16,10 +16,10 @@ from urllib.parse import urlparse
|
|
|
16
16
|
|
|
17
17
|
CONTRACT_VERSION = "0.1.0"
|
|
18
18
|
CONTRACT_REPOSITORY = "https://github.com/passioncode-ai/fabric-agent-contract"
|
|
19
|
-
CONTRACT_COMMIT = "
|
|
19
|
+
CONTRACT_COMMIT = "2eb91c00e852d9c31d804310d38fad91589fcbac"
|
|
20
20
|
# #region supported-contract-revisions — docs: README.md#contract-pin
|
|
21
21
|
# Only this declaration may name a legacy revision in live files.
|
|
22
|
-
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
22
|
+
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
23
23
|
# #endregion supported-contract-revisions
|
|
24
24
|
INTEROP_KEY = "https://fabric.passioncode.ai/agent-contract/extensions/interop/0.1"
|
|
25
25
|
MCP_REVISION = "2026-07-28"
|
|
@@ -116,8 +116,11 @@ def _run_problems(run: Any) -> List[str]:
|
|
|
116
116
|
return [] if match and 1 <= int(match.group(1)) <= 65535 else ["run.mcp.url is http://127.0.0.1:<port>/mcp"]
|
|
117
117
|
stdio = mcp["stdio"]
|
|
118
118
|
problems: List[str] = []
|
|
119
|
-
if not isinstance(stdio, dict) or not set(stdio) <= {"command", "env"} or "command" not in stdio:
|
|
120
|
-
return ["run.mcp.stdio is {command, env?}"]
|
|
119
|
+
if not isinstance(stdio, dict) or not set(stdio) <= {"command", "env", "scope"} or "command" not in stdio:
|
|
120
|
+
return ["run.mcp.stdio is {command, env?, scope?}"]
|
|
121
|
+
# DEC-0044, LC-19: where a host starts the server. A server started in every session is refused (FAC-SEM-056).
|
|
122
|
+
if "scope" in stdio and stdio["scope"] not in ("project", "on-demand"):
|
|
123
|
+
problems.append("run.mcp.stdio.scope is project or on-demand; a stdio server started in every session is refused (FAC-SEM-056, LC-19)")
|
|
121
124
|
command = stdio["command"]
|
|
122
125
|
if not isinstance(command, list) or not 1 <= len(command) <= 32 or not all(isinstance(a, str) and a for a in command):
|
|
123
126
|
problems.append("run.mcp.stdio.command is an argument array, never a shell string")
|
|
@@ -16,10 +16,10 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
16
16
|
compatibility: Python 3.9+ or Node.js 20+ for the kits; the probe needs Python 3.9+. launchd steps are macOS-only (Linux services use lifecycle manager none until a systemd adapter exists). Dashboard handoff optionally uses Fabric Dashboards MCP link/host_status/open; without it, report unresolved host capability. The contract checkout is optional.
|
|
17
17
|
metadata:
|
|
18
18
|
author: PassionCode.ai
|
|
19
|
-
version: "0.
|
|
19
|
+
version: "0.12.0"
|
|
20
20
|
contract-version: "0.1.0"
|
|
21
21
|
extension: "fabric-service/0.1"
|
|
22
|
-
extension-commit: "
|
|
22
|
+
extension-commit: "2eb91c00e852d9c31d804310d38fad91589fcbac"
|
|
23
23
|
---
|
|
24
24
|
|
|
25
25
|
# Building Fabric services
|
|
@@ -80,7 +80,10 @@ each manifest capability is the tool of its name, long work is a job with a stab
|
|
|
80
80
|
a question for a person is an elicitation, and every call carries one trace. Read
|
|
81
81
|
[the interop reference](references/interop.md) before writing an MCP tool; the helpers
|
|
82
82
|
are in [`scripts/fabric_interop.py`](scripts/fabric_interop.py) and
|
|
83
|
-
[`scripts/fabric-interop.mjs`](scripts/fabric-interop.mjs).
|
|
83
|
+
[`scripts/fabric-interop.mjs`](scripts/fabric-interop.mjs). When the callers are agents of the estate, the
|
|
84
|
+
service checks each call's delegation token (DEC-0039): read [the delegation reference](references/delegation.md);
|
|
85
|
+
the verifier is [`scripts/fabric_delegation.py`](scripts/fabric_delegation.py) /
|
|
86
|
+
[`scripts/fabric-delegation.mjs`](scripts/fabric-delegation.mjs).
|
|
84
87
|
|
|
85
88
|
## Step 2 — the non-negotiables
|
|
86
89
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Delegation — checking who acts for whom (DEC-0039)
|
|
2
|
+
|
|
3
|
+
A service that other agents of the estate call checks each call offline with the kit's verifier: the estate hub
|
|
4
|
+
signs a delegation token naming the person (`sub`), the actor chain (`act`), this service (`aud`), the
|
|
5
|
+
capabilities (`scope`) and the effect ceiling (`effect`); the service checks the signature against the estate's
|
|
6
|
+
published keys and answers `ok` or one refusal code. Contract: `docs/specification/delegation.md` (DL-1…DL-19)
|
|
7
|
+
at the pin. Python: [`scripts/fabric_delegation.py`](../scripts/fabric_delegation.py); Node:
|
|
8
|
+
[`scripts/fabric-delegation.mjs`](../scripts/fabric-delegation.mjs). Both answer the shared vectors exactly as the
|
|
9
|
+
contract's own verifier does.
|
|
10
|
+
|
|
11
|
+
## Contents
|
|
12
|
+
|
|
13
|
+
- Declaring it
|
|
14
|
+
- Wiring the gate
|
|
15
|
+
- Who must present a token
|
|
16
|
+
- Approvals
|
|
17
|
+
- What a refusal looks like
|
|
18
|
+
- Keys and the cache
|
|
19
|
+
- What the kit does not do
|
|
20
|
+
|
|
21
|
+
## Declaring it
|
|
22
|
+
|
|
23
|
+
In the well-known document: `surfaces.mcp.auth: "delegation"` (only delegation tokens) and
|
|
24
|
+
`auth.delegation: {issuer, jwks}` — the `iss` you trust (`urn:fabric:estate:<id>`) and where the key set is read.
|
|
25
|
+
The descriptor's token stays the host's: it is never a caller's credential on `/mcp` (DL-12). The probe checks
|
|
26
|
+
the declaration (`auth.delegation-declared`) and that `/mcp` refuses the descriptor token.
|
|
27
|
+
|
|
28
|
+
## Wiring the gate
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import fabric_delegation as fd, fabric_interop as fi
|
|
32
|
+
keys = fd.JwksCache(well_known["auth"]["delegation"]["jwks"]) # https, loopback http, or a file
|
|
33
|
+
gate = fd.delegation_gate(audience="example-agent", jwks=keys, issuer=well_known["auth"]["delegation"]["issuer"], # required
|
|
34
|
+
effects={"example.write": "draft", "example.publish": "publish"}) # each tool's manifest effect
|
|
35
|
+
server = fi.McpToolServer("example-agent", VERSION, authorize=gate) # pass the request headers to handle()
|
|
36
|
+
# in a handler: ctx.delegation["principal"], ["caller"], ["chain"] — record the chain with the work
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { JwksCache, delegationGate, refusalToolResult } from './fabric-delegation.mjs';
|
|
41
|
+
const gate = delegationGate({ audience: 'example-agent', jwks: new JwksCache(wk.auth.delegation.jwks), issuer: wk.auth.delegation.issuer,
|
|
42
|
+
effects: { 'example.write': 'draft' } });
|
|
43
|
+
const verdict = await gate(params.name, req.headers);
|
|
44
|
+
if (!verdict.ok) return refusalToolResult(verdict);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Who must present a token
|
|
48
|
+
|
|
49
|
+
DL-25 places each caller in a tier by its origin: **T0** a loopback caller under the owner's account that the
|
|
50
|
+
service's own local floor (the descriptor token, the Host guard) has authenticated; **T1** an enrolled machine of
|
|
51
|
+
the same owner; **T2** everyone else, and any call relayed onto loopback from off the machine (a tunnel, a proxy, the
|
|
52
|
+
hub forwarding a T2 caller). DL-26: a T0 or T1 caller is never required to present a token — pass the tier,
|
|
53
|
+
`gate(tool, headers, tier="T0")` or `server.handle(message, headers, tier="T0")`, and the call passes with no
|
|
54
|
+
delegation. A token such a caller presents is still verified and refused when invalid. A T2 caller takes the whole
|
|
55
|
+
profile. Money limits and human gates bind at every tier.
|
|
56
|
+
|
|
57
|
+
The token is read from `Fabric-Delegation` first (a forwarded call; present but empty is refused, never skipped),
|
|
58
|
+
then from `Authorization: Bearer` when the bearer is a delegation JWT (DL-9, DL-10). A tool with no declared
|
|
59
|
+
effect is refused (`unknown-state`), never guessed. The checks run in the DL-13 order; nothing about a token is
|
|
60
|
+
believed before its signature. The built-in job tools (`fabric.job.get`, `fabric.job.cancel`) are gated too: by the
|
|
61
|
+
job's own capability and effect, and only for the principal and caller that started the job (another caller is
|
|
62
|
+
`scope-not-granted`); `on_input` gets the checked delegation on its context. Start jobs with `ctx.start_job()` so the
|
|
63
|
+
job records who started it.
|
|
64
|
+
|
|
65
|
+
## Approvals
|
|
66
|
+
|
|
67
|
+
An action with an external effect may need the operator's approval (DL-17, DL-18). The order is fixed: the token,
|
|
68
|
+
then the grant check where there is one, then `verify_approval` / `verifyApproval`, which consumes the approval's
|
|
69
|
+
`jti` last, then the action. Without an approval, answer `approval-required` with
|
|
70
|
+
`action_digest(action)` / `actionDigest(action)` — the SHA-256 of the action's RFC 8785 form (`jcs`) — so the caller
|
|
71
|
+
can ask the hub. When the meter denies a grant check, answer `refusal_from_denial(denial)` /
|
|
72
|
+
`refusalFromDenial(denial)`: the meter's code unchanged, its window and level in `error.data` (DL-21 step 6). Keep consumed ids in `FileJtiStore` (0600, survives a restart); `MemoryJtiStore` is for tests
|
|
73
|
+
and `UNSAFE_NO_JTI_STORE` exists only by name. No store at all, or a store file that cannot be read, is
|
|
74
|
+
`unknown-state` — never a pass.
|
|
75
|
+
|
|
76
|
+
## What a refusal looks like
|
|
77
|
+
|
|
78
|
+
DL-19: an MCP tool answers `refusal_tool_result(r)` / `refusalToolResult(r)` — `isError: true` and
|
|
79
|
+
`structuredContent: {error: {code, message, data: {detail}}}`; an HTTP route answers `refusal_http(r)` /
|
|
80
|
+
`refusalHttp(r)` with the code's status (401 for `unauthenticated`, `token-expired`, `principal-unproven`, with
|
|
81
|
+
`WWW-Authenticate: Bearer error="invalid_token"`; 503 for `issuer-unavailable` and `unknown-state`; 403 for the
|
|
82
|
+
rest). A published key the service cannot use — of small order, for another use, or published twice — is the
|
|
83
|
+
issuer's fault, `issuer-unavailable` (DEC-0045); a gate without a trusted issuer refuses everything as
|
|
84
|
+
`no-trusted-issuer`. `detail` is a short machine word; the token, the approval and the keys never appear in a result or a log.
|
|
85
|
+
|
|
86
|
+
## Keys and the cache
|
|
87
|
+
|
|
88
|
+
`JwksCache` holds the estate's key set at most 10 minutes and, on a `kid` it does not hold, re-reads at most once
|
|
89
|
+
a minute (DL-15), and waits 10 s after a failed read before trying again; after 10 minutes without a successful read it answers nothing, and the verifier says
|
|
90
|
+
`issuer-unavailable`. It reads https, http on loopback only, or a file; a URL with credentials is refused. The
|
|
91
|
+
Python kit verifies Ed25519 itself (RFC 8032, standard library only, strict as OpenSSL: `S` below the group order,
|
|
92
|
+
canonical points, no small-order key); it follows no redirect when it reads the key set; the Node kit uses `node:crypto` and refuses small-order keys
|
|
93
|
+
itself (`isSmallOrderKey`), because Node before 26 lets OpenSSL accept a signature under one.
|
|
94
|
+
|
|
95
|
+
## What the kit does not do
|
|
96
|
+
|
|
97
|
+
It does not mint tokens, check attenuation against a parent (the issuer's rule, DL-5), check a grant or a spend
|
|
98
|
+
window (the meter's, DL-21), or decide which actions need an approval — the service decides that.
|
package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# fabric-service/0.1 — wire reference
|
|
2
2
|
|
|
3
|
-
Pinned to `fabric-agent-contract` commit `
|
|
3
|
+
Pinned to `fabric-agent-contract` commit `2eb91c00e852d9c31d804310d38fad91589fcbac`
|
|
4
4
|
(`docs/specification/service.md`, DEC-0015; the usage report DEC-0021; Windows and Linux supervision
|
|
5
5
|
DEC-0032 and DEC-0033; the operator channel DEC-0034 and DEC-0035; the embedded dashboard DEC-0036;
|
|
6
|
-
delegation and the operator session's lifetime DEC-0039
|
|
6
|
+
delegation and the operator session's lifetime DEC-0039; the meter's call window DEC-0041; session handoff DEC-0042;
|
|
7
|
+
canonical forms DEC-0043; `degraded[].setup` and `run.mcp.stdio.scope` DEC-0044; delegation sealed and trust tiers
|
|
8
|
+
DEC-0045). The contract's schemas are normative;
|
|
7
9
|
this page is the working summary. Extension key:
|
|
8
10
|
`https://fabric.passioncode.ai/agent-contract/extensions/service/0.1`.
|
|
9
11
|
|
|
@@ -56,6 +58,9 @@ No auth; the Host/Origin guard applies; answered from memory in under 100 ms.
|
|
|
56
58
|
```
|
|
57
59
|
|
|
58
60
|
- `status`: `starting | ready | degraded | stopping`. No answer means `down`.
|
|
61
|
+
- A `degraded[]` entry may carry `setup: true` (DEC-0044): the source waits for a person to finish setting it up
|
|
62
|
+
(a key not entered, a model not chosen). It is not an outage, and a watcher does not alert on it. The kits pass
|
|
63
|
+
entries through unchanged.
|
|
59
64
|
- `build` needs `commit` or `digest` (`sha256:<64 hex>`).
|
|
60
65
|
- `summary`: at most six tiles; `attention: true` counts toward the host's badge.
|
|
61
66
|
- `surfaces.events` is required; `dashboard` and `mcp` when the service has them; `usage`
|
|
@@ -72,7 +77,7 @@ No auth; the Host/Origin guard applies; answered from memory in under 100 ms.
|
|
|
72
77
|
the MCP surface takes only the estate's delegation tokens, and the top-level
|
|
73
78
|
`auth.delegation {issuer, jwks}` is then required. With `own` or `delegation` the descriptor's
|
|
74
79
|
token is not an MCP credential: a host and the probe never call `/mcp` with it as a caller.
|
|
75
|
-
The kits
|
|
80
|
+
The kits verify them with `fabric_delegation` / `fabric-delegation.mjs` ([delegation](delegation.md)).
|
|
76
81
|
|
|
77
82
|
## Events page — `GET /fabric/v1/events?after=<cursor>&limit=<n>`
|
|
78
83
|
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
- **Delegation (DEC-0039, DL-16).** `surfaces.mcp.auth: "delegation"` means `/mcp` takes only
|
|
16
16
|
the estate's delegation tokens; declare `auth.delegation {issuer, jwks}` in the well-known
|
|
17
17
|
document. The probe treats it like `own` and checks the declaration
|
|
18
|
-
(`auth.delegation-declared`). The kits
|
|
19
|
-
|
|
18
|
+
(`auth.delegation-declared`). The kits verify the tokens: put `delegation_gate` /
|
|
19
|
+
`delegationGate` in front of the tools — see [the delegation reference](delegation.md).
|
|
20
20
|
- Register it into a client config with the service's own command
|
|
21
21
|
(`<tool> mcp-register`), which writes `{"type":"http","url":"http://127.0.0.1:<port>/mcp","headers":{...}}`
|
|
22
22
|
atomically, aborts if the file changed meanwhile, and keeps one 0600 backup. The token
|