@passioncode-ai/fabric-agent-adapter 0.21.0 → 0.23.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/CHANGELOG.md +112 -0
- package/README.md +38 -6
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +2 -2
- package/plugins/fabric-agent-adapter/hooks/hooks.json +43 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -3
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +10 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/estate-record.md +32 -15
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +46 -14
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +4 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +5 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +35 -20
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +77 -9
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +167 -36
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +53 -19
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +107 -16
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +270 -49
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +8 -2
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +217 -0
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +99 -0
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +111 -0
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +1265 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.23.0 - 2026-10-13
|
|
4
|
+
|
|
5
|
+
The contract pin moves from `b291bf0` (DEC-0055) to contract `main` `fe55fc6`, and both kits follow every rule in that
|
|
6
|
+
range that touches what they already do (FAA-32; the contract's hand-over of 2026-10-12, its CT-18 row). `b291bf0`
|
|
7
|
+
joins the supported revisions. What the range adds beyond that is its own row: FAA-33…37.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **The supervisor marker comes as an argument too** (DEC-0057, CT-01, P4-01): `supervisor_marker` /
|
|
12
|
+
`supervisorMarker` read `FABRIC_SERVICE_SUPERVISOR=<manager>` and `--fabric-supervisor <manager>` /
|
|
13
|
+
`--fabric-supervisor=<manager>` (after the executable, before `--`; a bare flag consumes no `--…` token), with `node`
|
|
14
|
+
among the managers. Markers that disagree — the two forms, the argument twice, a bare or empty argument beside the
|
|
15
|
+
variable — exit 75 at once, before the lock, naming both. `supervised()` and `supervised_by_launchd()` take the
|
|
16
|
+
marker; `hold_single_instance` / `holdSingleInstance` take `env` and `argv`. A holder whose pid cannot be read is
|
|
17
|
+
named unknown (`FAC-SEM-078`).
|
|
18
|
+
- **Writers:** `task_xml` / `taskXml` write `--fabric-supervisor task-scheduler` in the task's `Arguments`, before any
|
|
19
|
+
`--` (a task's action carries no environment, so a Task Scheduler copy now waits like one under launchd);
|
|
20
|
+
`systemd_unit` / `systemdUnit` set the variable unconditionally; every writer refuses a marker in the program
|
|
21
|
+
arguments. `add_supervisor_argument(parser)` lets a service's argparse accept the flag; the sample service uses it.
|
|
22
|
+
- **DL-HUBKEY** (DEC-0060): `hub_key_certified` / `hubKeyCertified(record, kid, x, at, applied, extra)` answer the
|
|
23
|
+
contract's verdict — `{certified, machine, revision}` or `{certified: false, fault, detail}` — instead of a boolean.
|
|
24
|
+
A revision outside its window, unreadable, lower than the applied one or forking it is the trust source's fault
|
|
25
|
+
(`issuer-unavailable`: `estate-outside-window`, `estate-unreadable`, `estate-rolled-back`, `estate-forked`); a `kid`
|
|
26
|
+
on two machines, a missing `x` and a numeric `kid` never certify; revocation refs compare exactly. The verifiers
|
|
27
|
+
take `estate_applied` / `estateApplied` and `estate_revocations` / `estateRevocations`; in the Node kit only an
|
|
28
|
+
absent `estate` skips the check (`null` is an unreadable source). Every verifier refuses a clock that is not a number
|
|
29
|
+
of seconds `unknown-state` `no-clock` before row 1.
|
|
30
|
+
- **The estate record** (DEC-0063, DEC-0066): `verify_estate_record` / `verifyEstateRecord` admit `issuedAt` up to 60 s
|
|
31
|
+
ahead (`CLOCK_SKEW_SECONDS`); the signing passkey must be under a `sign.<domain>` RP (`wrong-rp`) and its origins
|
|
32
|
+
within it (`wrong-origin`); the record's rules add `FAC-SEM-092`.
|
|
33
|
+
- **The Windows token-file reader** (DEC-0057, `FAC-SEM-079`): `windows_token_acl_problem` /
|
|
34
|
+
`windowsTokenAclProblem` decide over the file's flags, owner and ACEs `{type, sid, mask}`: an object or callback ACE
|
|
35
|
+
is refused, an allow with an empty mask and every deny grant nothing, SIDs compare case-insensitively, anything
|
|
36
|
+
unreadable is refused. The Python kit reads the ACEs from SDDL (`acl_from_sddl`), the Node kit through .NET's raw
|
|
37
|
+
descriptor with the mask read unsigned. `windows_acl` / `windowsAcl` now answer ACEs; `token_acl_problem` /
|
|
38
|
+
`tokenAclProblem` are replaced by `token_file_problem` / `tokenFileProblem`.
|
|
39
|
+
- **The descriptor** (DEC-0057 item 5): `label` and `plist` are refused beside `systemd` and `task-scheduler`; a
|
|
40
|
+
`localPath` starting `//` or `/\` is a share and refused.
|
|
41
|
+
|
|
42
|
+
### Evidence
|
|
43
|
+
|
|
44
|
+
- Vendored from the contract at `fe55fc6` and re-answered by its own functions (`test/fixtures/contract/vendor_vectors.mjs`):
|
|
45
|
+
`hub-key-vectors.json` (51 cases, 14 verifier answers; the hub seeds dropped), `supervisor-vectors.json` (22 marker
|
|
46
|
+
cases, 11 `FAC-SEM-078` records), `windows-token-vectors.json` (30 cases), `descriptor-negatives.json` (DEC-0057's
|
|
47
|
+
seven); `estate-vectors.json` regenerated (49 verify cases). Both kits answer every case as the contract does.
|
|
48
|
+
- The kits' own starts against a held lock — by hand, the node, a task, an unknown holder, three conflicts — are
|
|
49
|
+
recorded and read by a port of `lockOutcomeRules` that itself reads the contract's 11 records as it does.
|
|
50
|
+
- The sample service, started with `--fabric-supervisor=node`, serves a well-known document, usage report and events
|
|
51
|
+
page valid under the `fe55fc6` schemas; the descriptors the kit writes under every manager are valid too.
|
|
52
|
+
- 34 planted defects, all caught.
|
|
53
|
+
- The `--fabric-supervisor` scenario eval (`supervised-by-argument`) was written before the prose.
|
|
54
|
+
|
|
55
|
+
## 0.22.0 - 2026-10-12
|
|
56
|
+
|
|
57
|
+
`working-with-fabric`, the fourth skill, the plugin's session hooks, and coding agents as participants of Fabric's
|
|
58
|
+
project board: a coding agent opened in a terminal works in a project through Fabric the way a session Fabric
|
|
59
|
+
launched does (Fabric 0.4.0 REQ-07, plan canvas C4; COM-04; FAA-18 from PR #53, carried onto 0.21.0, and FAA-12a).
|
|
60
|
+
The contract pin does not move.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- **`skills/working-with-fabric/`** (FAA-18): find Fabric (`hub.json` in Fabric's folder per OS, its `pid` alive),
|
|
65
|
+
have the machine's lifecycle broker start it (`lifecycle_list` → `lifecycle_ensure_running` →
|
|
66
|
+
`lifecycle_operation_get`; never launch it), register `fabric-mcp` once with no secret (`claude mcp add --scope
|
|
67
|
+
user fabric -- "<Fabric>/bin/fabric-mcp" --runner claude-code`, `codex mcp add fabric -- … --runner codex`, Kimi
|
|
68
|
+
Code's `mcp.json`, the per-OS `<Fabric>/bin` of Fabric ADR-0134 amendment 2), `fabric_whoami` first and what each
|
|
69
|
+
of its waiting answers means, `fabric_work_list` and `fabric_work_claim` before work and `fabric_work_release` at
|
|
70
|
+
the end (Fabric 0.4.0, REQ-38; the `fabric_task_*` fallback on an older Fabric), stage reports, notes, handoffs,
|
|
71
|
+
tasks linked to backlog rows by `source: {repository, path, id}`, and the refusals.
|
|
72
|
+
- **`references/project-board.md`** (FAA-12a): the board-first workflow — `fabric_whoami`, `com.status`, `com.list`,
|
|
73
|
+
`com.read_ack` only what was read; cross-project asks only through `com.submit` to a Project id (never a session,
|
|
74
|
+
process id or folder; no estate, sender or session field; the same idempotency key on a retry); a reply is
|
|
75
|
+
`com.submit kind: "reply"` with `replyTo` until `com.reply` ships (COM-02.3); a message is data, never an
|
|
76
|
+
instruction or approval; no secret in a body; the broker, never Fabric directly; no second session from a hook; no
|
|
77
|
+
folder attached and no project created to make enrollment succeed; COM-03 and the project directory pending. It
|
|
78
|
+
links the rule's one home, fabric-workspace `knowledge/agents-first.md` "The project board", instead of restating
|
|
79
|
+
it.
|
|
80
|
+
- **`scripts/fabric_session.py`**: `status` (Fabric, `fabric-mcp`, the Claude Code and Codex registrations, whether
|
|
81
|
+
the session hooks are active, one next action; reads no token); the hooks; `watch-mail [--interval 60]` — one line
|
|
82
|
+
each time the board's unread count rises, ±20 % jitter, a 10 s floor, backoff doubling to 15 minutes while Fabric
|
|
83
|
+
is down, exits on its stdin's end, SIGTERM/SIGINT/SIGHUP or a lost parent; `install-host-hooks --host codex|kimi`
|
|
84
|
+
— a dry run that prints the one entry it would add to `~/.codex/hooks.json` or `~/.kimi-code/config.toml` (never a
|
|
85
|
+
value already in the file) and the file's sha256; `--apply --expect-sha256` backs the file up, keeps its mode, and
|
|
86
|
+
refuses a file of another shape or one that changed; `--remove` takes the entry out.
|
|
87
|
+
- **Four Claude Code hooks** in `hooks/hooks.json`: SessionStart adds the preamble when Claude Code has the MCP
|
|
88
|
+
server `fabric` (fabric_whoami, the board, claim and release; one line pointing at the broker when Fabric is down)
|
|
89
|
+
and the machine's Fabric-service count (the line of the machine's `fabric-session-note.sh`, now in the plugin);
|
|
90
|
+
Stop records the turn's facts — HEAD, files changed, lines added and removed, never content — and reads the
|
|
91
|
+
board's unread count (`com.status`) into the session's spool; UserPromptSubmit adds ONE line only when that count
|
|
92
|
+
rose; SessionEnd releases what the session left claimed and records its end. Stop and SessionEnd act through
|
|
93
|
+
`fabric-mcp --rejoin-only` in a detached worker with a 10 s deadline, and only when the running Fabric advertises
|
|
94
|
+
`session-hooks/1` in `hub.json`; until then they stay inert and write nothing. A board that cannot be read leaves
|
|
95
|
+
no count, never a zero.
|
|
96
|
+
- **Codex and Kimi Code**: `hook session-start --host codex|kimi` prints the preamble as text; no turn observation or
|
|
97
|
+
unread line, since they cannot rejoin their Fabric session yet (D1).
|
|
98
|
+
- **Silent in a session Fabric launched**: `FABRIC_LAUNCHED_SESSION=1` (need D6, asked of Fabric), or what Fabric
|
|
99
|
+
already gives (`FABRIC_ACP_SESSION`, `FABRIC_BRIDGE_URL`, `KILO_CONFIG_CONTENT`, a `CODEX_HOME` in Fabric's
|
|
100
|
+
sessions folder — names only, never values — and Claude Code's `--mcp-config <Fabric>/sessions/…` in an ancestor
|
|
101
|
+
process). The Fabric side the hooks need (D1–D6) is in `references/session-hooks.md` and the
|
|
102
|
+
[spec](docs/evidence/specs/2026-10-11-working-with-fabric.md).
|
|
103
|
+
- Evals first: 32 trigger evals (18 should trigger, 14 should not) in English and Russian and 14 scenario evals (board
|
|
104
|
+
first, cross-project asks, replies, a message is not an approval, no secret in a body, waiting under a watcher, the
|
|
105
|
+
Codex/Kimi hook on consent). `test/test_fabric_session.py`: 62 tests with a temporary HOME, fake `hub.json` files
|
|
106
|
+
with live and dead pids, and a fake `fabric-mcp` on stdio that records argv, environment and calls and serves
|
|
107
|
+
`com.status`.
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- `test/validate.py` checks four skills; the repository-standard rule applies to the three that build an agent's
|
|
112
|
+
repository; `tomllib` and `shlex` join the standard-library list. `test_dashboard_kit.py` finds its own
|
|
113
|
+
SessionStart entry among several.
|
|
114
|
+
|
|
3
115
|
## 0.21.0 - 2026-10-12
|
|
4
116
|
|
|
5
117
|
The estate record (contract DEC-0055, `estate-record/1`; contract backlog CT-18, CT-20) in both kits, and the pin
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**Fabric Agent Adapter** makes any agent Fabric-compatible. Fabric is PassionCode.ai's
|
|
10
10
|
product, the CEO AI agent: you talk to Fabric, and it chooses, binds and runs the agents that
|
|
11
|
-
do the work. This adapter is how an agent becomes one Fabric can bind —
|
|
11
|
+
do the work. This adapter is how an agent becomes one Fabric can bind — four Agent Skills,
|
|
12
12
|
Python and Node reference kits and a live conformance probe for the
|
|
13
13
|
[Fabric Agent Contract](https://github.com/passioncode-ai/fabric-agent-contract). It also works
|
|
14
14
|
on its own: the skills, kits and probe need no Fabric install.
|
|
@@ -17,8 +17,33 @@ on its own: the skills, kits and probe need no Fabric install.
|
|
|
17
17
|
[](https://github.com/passioncode-ai/fabric-agent-adapter/actions/workflows/validate.yml)
|
|
18
18
|
[](LICENSE)
|
|
19
19
|
|
|
20
|
-
The skills are `adapting-projects-to-fabric`, `creating-fabric-agents
|
|
21
|
-
`building-fabric-services`.
|
|
20
|
+
The skills are `adapting-projects-to-fabric`, `creating-fabric-agents`,
|
|
21
|
+
`building-fabric-services` and `working-with-fabric`.
|
|
22
|
+
|
|
23
|
+
`working-with-fabric` is for the other side: a coding agent (Claude Code, Codex, Kimi Code, Kilo, Hermes) opened in
|
|
24
|
+
a terminal that works in a project through Fabric. It finds Fabric (`hub.json`, its `pid`), has the machine's
|
|
25
|
+
lifecycle broker start it when it is down, registers `fabric-mcp` once with no secret, calls `fabric_whoami`
|
|
26
|
+
first, reads the project board (`com.status`, `com.list`, `com.read_ack` only what was read) and asks other
|
|
27
|
+
Projects only through `com.submit`, asks who is working on what and claims its task before it starts
|
|
28
|
+
(`fabric_work_list`, `fabric_work_claim`, Fabric 0.4.0), links tasks to backlog rows instead of copying them, and
|
|
29
|
+
releases at the end (`fabric_work_release`). `scripts/fabric_session.py status` prints where Fabric stands and one
|
|
30
|
+
next action:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python3 plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py status
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
In Claude Code the plugin adds four session hooks: SessionStart puts that preamble into the session when the MCP
|
|
37
|
+
server `fabric` is registered (one line pointing at the broker when Fabric is down), with the machine's
|
|
38
|
+
Fabric-service count; Stop records each turn's facts (HEAD, files changed, lines added and removed — never content)
|
|
39
|
+
and the board's unread count; UserPromptSubmit adds one line only when that count rose; SessionEnd releases what the
|
|
40
|
+
session left claimed. Stop, UserPromptSubmit and SessionEnd act only when the running Fabric advertises
|
|
41
|
+
`session-hooks/1`. All are silent in a session Fabric launched, never block the session, read no token and always
|
|
42
|
+
exit 0. `fabric_session.py watch-mail` waits for board mail under a background watcher, and `install-host-hooks
|
|
43
|
+
--host codex|kimi` adds the session-start preamble to Codex or Kimi Code (a dry run unless `--apply`). The
|
|
44
|
+
[hooks reference](plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md) lists what
|
|
45
|
+
they need from Fabric; the [board reference](plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md)
|
|
46
|
+
is the board-first workflow.
|
|
22
47
|
|
|
23
48
|
`building-fabric-services` makes an agent a long-lived local service with a dashboard
|
|
24
49
|
that is always alive, runs as one copy, keeps its state through a reinstall and appears
|
|
@@ -40,12 +65,12 @@ box, sticky chrome at most 120 px — with seven WCAG AA themes (light and dark)
|
|
|
40
65
|
`fabric_appearance` cookie. `scripts/dashboard_kit.py install|status` copies and checks it,
|
|
41
66
|
`scripts/check_dashboard_layout.mjs` measures a rendered page in WebKit at 360, 480, 768 and 1280 px
|
|
42
67
|
(Playwright; `NOT_RUN` without it), and the probe's `dashboard.declared` checks the declaration. The
|
|
43
|
-
plugin's
|
|
68
|
+
plugin's dashboard-kit hook (SessionStart) prints a single line in a repository whose dashboard has no kit or an
|
|
44
69
|
older one, and nothing anywhere else; the [kit reference](plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md)
|
|
45
70
|
has the upgrade steps, taken only with the operator's go-ahead.
|
|
46
71
|
|
|
47
72
|
Dashboard handoffs use the host-generated `open_link` as the primary action. The
|
|
48
|
-
three skills carry the same [consumer procedure](plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md)
|
|
73
|
+
three builder skills carry the same [consumer procedure](plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md)
|
|
49
74
|
and a portable `scripts/check_dashboard_link.py` gate for generated renderers.
|
|
50
75
|
It rejects primary HTTP when the host is available, failed-host browser fallback,
|
|
51
76
|
and local links addressed to another device. A skill install alone does not filter
|
|
@@ -98,6 +123,7 @@ Generic Agent Skills clients:
|
|
|
98
123
|
npx skills add passioncode-ai/fabric-agent-adapter --skill adapting-projects-to-fabric
|
|
99
124
|
npx skills add passioncode-ai/fabric-agent-adapter --skill creating-fabric-agents
|
|
100
125
|
npx skills add passioncode-ai/fabric-agent-adapter --skill building-fabric-services
|
|
126
|
+
npx skills add passioncode-ai/fabric-agent-adapter --skill working-with-fabric
|
|
101
127
|
```
|
|
102
128
|
|
|
103
129
|
### Configure
|
|
@@ -178,6 +204,12 @@ Or, for an agent that does not exist yet:
|
|
|
178
204
|
Create a new fabric-compatible agent for <capability>; its consumer is <who calls it>.
|
|
179
205
|
```
|
|
180
206
|
|
|
207
|
+
Or, in a coding agent opened in a project folder:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
Work on backlog row FAA-18 through Fabric: check who is working here, claim it, and release it when done.
|
|
211
|
+
```
|
|
212
|
+
|
|
181
213
|
Or run the deterministic helper directly:
|
|
182
214
|
|
|
183
215
|
```bash
|
|
@@ -203,7 +235,7 @@ Scaffolding is non-destructive by default. It writes only the paths declared in
|
|
|
203
235
|
The default pin for new bundles is [`fabric-contract.lock.json`](fabric-contract.lock.json):
|
|
204
236
|
|
|
205
237
|
- version: `0.1.0`
|
|
206
|
-
- commit: `
|
|
238
|
+
- commit: `fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0`
|
|
207
239
|
|
|
208
240
|
Every other mention of the default contract revision — this section, the skills' metadata, the
|
|
209
241
|
skill card, `adapt_project.py` — must equal it; `python3 test/validate.py` fails a tree
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/fabric-agent-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Create Fabric-compatible agents, run them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract. This package is the installer CLI.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "python3 test/validate.py && python3 -m unittest discover -s test -q && node --test 'test/*.test.mjs'"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "fabric-agent-adapter",
|
|
4
4
|
"displayName": "Fabric Agent Adapter",
|
|
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.
|
|
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; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
|
|
6
|
+
"version": "0.23.0",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "Two silent-unless-relevant hook sets. The dashboard-kit notice: one line at session start in a repository whose Fabric dashboard has no kit or an older one (fabric-dashboard/0.1, DEC-0036). The Fabric session hooks (working-with-fabric, COM-04, FAA-12a): at session start the preamble when Claude Code has the MCP server `fabric` (fabric_whoami, then the project board through com.status and com.list, claim and release), and the machine's Fabric-service count; each turn's facts (HEAD, files changed, lines added and removed, never content), the board's unread count and the session's end through Fabric, only when the running Fabric advertises session-hooks/1; at each prompt one line only when the unread count rose. All silent in a session Fabric launched. Every hook reads no token, prints at most one block, always exits 0, and hands any Fabric call to a detached worker with a 10 s deadline.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -11,6 +11,48 @@
|
|
|
11
11
|
"timeout": 5
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "python3 -S \"${CLAUDE_PLUGIN_ROOT}/skills/working-with-fabric/scripts/fabric_session.py\" hook session-start",
|
|
20
|
+
"timeout": 5
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"Stop": [
|
|
26
|
+
{
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "python3 -S \"${CLAUDE_PLUGIN_ROOT}/skills/working-with-fabric/scripts/fabric_session.py\" hook stop",
|
|
31
|
+
"timeout": 5
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"SessionEnd": [
|
|
37
|
+
{
|
|
38
|
+
"hooks": [
|
|
39
|
+
{
|
|
40
|
+
"type": "command",
|
|
41
|
+
"command": "python3 -S \"${CLAUDE_PLUGIN_ROOT}/skills/working-with-fabric/scripts/fabric_session.py\" hook session-end",
|
|
42
|
+
"timeout": 5
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"UserPromptSubmit": [
|
|
48
|
+
{
|
|
49
|
+
"hooks": [
|
|
50
|
+
{
|
|
51
|
+
"type": "command",
|
|
52
|
+
"command": "python3 -S \"${CLAUDE_PLUGIN_ROOT}/skills/working-with-fabric/scripts/fabric_session.py\" hook user-prompt-submit",
|
|
53
|
+
"timeout": 5
|
|
54
|
+
}
|
|
55
|
+
]
|
|
14
56
|
}
|
|
15
57
|
]
|
|
16
58
|
}
|
|
@@ -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.23.0"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0"
|
|
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 `fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0`.
|
|
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
|
package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py
CHANGED
|
@@ -21,10 +21,10 @@ import fabric_secrets as _secrets # noqa: E402 - the contract's credential dete
|
|
|
21
21
|
|
|
22
22
|
CONTRACT_VERSION = "0.1.0"
|
|
23
23
|
CONTRACT_REPOSITORY = "https://github.com/passioncode-ai/fabric-agent-contract"
|
|
24
|
-
CONTRACT_COMMIT = "
|
|
24
|
+
CONTRACT_COMMIT = "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0"
|
|
25
25
|
# #region supported-contract-revisions — docs: README.md#contract-pin
|
|
26
26
|
# Only this declaration may name a legacy revision in live files.
|
|
27
|
-
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
27
|
+
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "b291bf09e0a9f9fd3c16cf540832cd021203b7d1", "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
28
28
|
# #endregion supported-contract-revisions
|
|
29
29
|
INTEROP_KEY = "https://fabric.passioncode.ai/agent-contract/extensions/interop/0.1"
|
|
30
30
|
MCP_REVISION = "2026-07-28"
|
|
@@ -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 install a systemd user unit and Windows ones a per-user Scheduled Task with the kits' writers. 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.23.0"
|
|
20
20
|
contract-version: "0.1.0"
|
|
21
21
|
extension: "fabric-service/0.1"
|
|
22
|
-
extension-commit: "
|
|
22
|
+
extension-commit: "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0"
|
|
23
23
|
---
|
|
24
24
|
|
|
25
25
|
# Building Fabric services
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md
CHANGED
|
@@ -95,16 +95,19 @@ itself (`isSmallOrderKey`), because Node before 26 lets OpenSSL accept a signatu
|
|
|
95
95
|
|
|
96
96
|
## Keys the estate record certifies
|
|
97
97
|
|
|
98
|
-
A verifier that also reads the estate's record (DEC-0055, [the estate record reference](estate-record.md))
|
|
99
|
-
`kid` only while
|
|
100
|
-
verified revision as `estate=` / `{ estate }`, as a value or as a function returning it,
|
|
98
|
+
A verifier that also reads the estate's record (DEC-0055, DEC-0060, [the estate record reference](estate-record.md))
|
|
99
|
+
trusts a `kid` only while the revision it reads certifies it (DL-14, row 4a, right after the signature). Pass the
|
|
100
|
+
current verified revision as `estate=` / `{ estate }`, as a value or as a function returning it, with
|
|
101
|
+
`estate_applied` / `estateApplied` and `estate_revocations` / `estateRevocations`, to `delegation_gate`,
|
|
101
102
|
`verify_delegation` or `verify_approval`.
|
|
102
|
-
- An uncertified `kid` is
|
|
103
|
+
- An uncertified `kid` is the token's fault: `unauthenticated` (`approval-invalid` for an approval), detail
|
|
103
104
|
`kid-not-certified`.
|
|
104
|
-
-
|
|
105
|
+
- A revision that cannot be read, is outside its window, is lower than the applied one or forks it is the trust
|
|
106
|
+
source's fault: `issuer-unavailable`, detail `estate-unreadable`, `estate-outside-window`, `estate-rolled-back` or
|
|
107
|
+
`estate-forked`.
|
|
105
108
|
- Without `estate`, nothing changes.
|
|
106
|
-
-
|
|
107
|
-
|
|
109
|
+
- Every verifier refuses a clock that is not a number of seconds `unknown-state` `no-clock` before row 1: a NaN clock
|
|
110
|
+
would make every time row false and pass an expired token.
|
|
108
111
|
|
|
109
112
|
## What the kit does not do
|
|
110
113
|
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/estate-record.md
CHANGED
|
@@ -43,12 +43,16 @@ It checks, in the order of the ER table:
|
|
|
43
43
|
parent, and no revocation dropped.
|
|
44
44
|
5. **The signer.** The signing passkey must be among the trusted ones and not revoked by the parent. A revision may
|
|
45
45
|
revoke its own signer: that is rotation.
|
|
46
|
-
6. **The assertion.**
|
|
46
|
+
6. **The assertion.** The passkey is a signing credential (DEC-0063): an RP ID that is not a dedicated signing RP,
|
|
47
|
+
`sign.<domain>` in lower case, is `wrong-rp` before the assertion is read, and an origin outside the RP ID is not
|
|
48
|
+
pinned, so a ceremony that ran there is `wrong-origin`.
|
|
47
49
|
- Client data: type, challenge, origin, no cross-origin use.
|
|
48
50
|
- The RP ID hash, and the user-presence and user-verification flags.
|
|
49
51
|
- The signature: ES256 or EdDSA, under a key validated first (a valid P-256 point; an Ed25519 key of full order).
|
|
50
|
-
7. **The window.** At most 30 days.
|
|
51
|
-
|
|
52
|
+
7. **The window.** At most 30 days. A revision may be issued up to 60 s ahead of the verifier's clock (DEC-0066,
|
|
53
|
+
`CLOCK_SKEW_SECONDS`); earlier than that it is `not-yet-valid`.
|
|
54
|
+
8. **The record's own rules.** A violation is `rule-violation` with its `codes`, `FAC-SEM-072…076` and `FAC-SEM-092`
|
|
55
|
+
(each passkey the record lists is a signing credential, its origins within its RP ID).
|
|
52
56
|
|
|
53
57
|
Dates are strict RFC 3339: a `T`, an offset, and a day that exists. `:60` and a space are refused. Passkey JWK `x`
|
|
54
58
|
and `y` must be canonical base64url. The Python kit verifies ES256 in pure Python (P-256, strict DER), and the Node
|
|
@@ -56,22 +60,35 @@ kit through `node:crypto`.
|
|
|
56
60
|
|
|
57
61
|
## Trusting a delegation key
|
|
58
62
|
|
|
59
|
-
A delegation verifier that reads the estate record trusts a token's `kid` only while
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
A delegation verifier that reads the estate record trusts a token's `kid` only while the revision it reads certifies
|
|
64
|
+
it (DL-14, contract DEC-0060): exactly one machine's `hubKey` has that `kid` and the published key's `x`, the clock is
|
|
65
|
+
inside the revision's window (from 60 s before `issuedAt`, DEC-0066, to `validUntil`), and neither the revision nor the
|
|
66
|
+
revocation delta's entries applied since it revoke `hub-key <kid>` or `machine <id>`. It is checked right after the
|
|
67
|
+
signature (DL-13 row 4a). Give the gate the current verified revision, or a function that returns it, the highest
|
|
68
|
+
revision the machine applied, and the delta's revocations:
|
|
62
69
|
|
|
63
70
|
```python
|
|
64
|
-
gate = fd.delegation_gate(audience=..., jwks=keys, issuer=..., effects=..., estate=lambda: current
|
|
71
|
+
gate = fd.delegation_gate(audience=..., jwks=keys, issuer=..., effects=..., estate=lambda: current,
|
|
72
|
+
estate_applied={"revision": applied_number, "digest": applied_digest},
|
|
73
|
+
estate_revocations=lambda: delta_entries)
|
|
65
74
|
```
|
|
66
75
|
|
|
67
|
-
-
|
|
68
|
-
`approval-invalid`) with detail `kid-not-certified`.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
- **The token's fault** — no such certification, another key under that `kid`, a `kid` on two machines, a revoked hub
|
|
77
|
+
key or machine — is `unauthenticated` (for an approval, `approval-invalid`) with detail `kid-not-certified`.
|
|
78
|
+
- **The trust source's fault** is `issuer-unavailable`: `estate-unreadable` (a source that throws or answers nothing
|
|
79
|
+
readable, a revision without a number or digest, a window of zero or over 30 days, dates read strictly, `machines` or
|
|
80
|
+
`revocations` not arrays), `estate-outside-window`, `estate-rolled-back` (lower than the applied revision) and
|
|
81
|
+
`estate-forked` (the applied number with another digest). A caller cannot cure these by minting again.
|
|
82
|
+
- An unreadable clock — not a finite number of seconds a `Date` can hold — is refused `unknown-state` `no-clock`
|
|
83
|
+
before row 1, in every verifier.
|
|
84
|
+
- Only an absent `estate` skips the check. In the Node kit `null` is an unreadable source; in Python, where `None` is
|
|
85
|
+
the absent value, pass a function returning `None` for a source that has nothing.
|
|
86
|
+
- **What you pass in.** Pass only a revision that `verify_estate_record` accepted and whose number is not lower than
|
|
87
|
+
the highest the machine applied; a higher one only when you verified its chain from the applied revision.
|
|
88
|
+
- `hub_key_certified(record, kid, x, at, applied, extra_revocations)` /
|
|
89
|
+
`hubKeyCertified(record, kid, x, at, applied, {extraRevocations})` answers the question on its own:
|
|
90
|
+
`{certified: true, machine, revision}` or `{certified: false, fault, detail}`. Both kits are held to the contract's
|
|
91
|
+
`fixtures/vectors/hub-key.json` (`test/fixtures/contract/hub-key-vectors.json`).
|
|
75
92
|
|
|
76
93
|
## Checking a record you produce
|
|
77
94
|
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md
CHANGED
|
@@ -73,12 +73,36 @@ operator's real jobs.
|
|
|
73
73
|
## One copy under a supervisor
|
|
74
74
|
|
|
75
75
|
Started by hand, a copy that finds `service.lock` held prints one sentence naming the
|
|
76
|
-
holder
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
holder (or saying the holder is unknown, when its pid cannot be read) and exits 75 at once.
|
|
77
|
+
Under launchd that exit is a respawn every `ThrottleInterval` (10 s), forever, and under
|
|
78
|
+
systemd one every `RestartSec`. So a copy its supervisor started, and that says so with the
|
|
79
|
+
**supervisor marker**, backs off in-process — 0.5 s doubling to 30 s, 300 s in all — takes over
|
|
80
|
+
if the holder leaves, and exits 75 only when the wait runs out: a few starts an hour instead of
|
|
81
|
+
360. It touches nothing while it waits. Two installs sharing one data directory are still the
|
|
82
|
+
defect to remove; the back-off only stops the loop from costing the machine.
|
|
83
|
+
|
|
84
|
+
The marker (contract DEC-0057, CT-01) is the variable `FABRIC_SERVICE_SUPERVISOR=<manager>` or
|
|
85
|
+
the argument `--fabric-supervisor <manager>` (also `--fabric-supervisor=<manager>`), after the
|
|
86
|
+
executable and before any `--`; `<manager>` is `launchd`, `systemd`, `task-scheduler` or `node`
|
|
87
|
+
(Project Observatory's node, which supervises the services it starts). The writer of the
|
|
88
|
+
supervisor file writes it: `launchd_plist` and `systemd_unit` / `systemdUnit` set the variable,
|
|
89
|
+
always; `task_xml` / `taskXml` put the argument in the task's `Arguments`, because a task's action
|
|
90
|
+
carries no environment. Each writer refuses a marker already in the program arguments. A copy
|
|
91
|
+
never infers supervision from its parent process.
|
|
92
|
+
|
|
93
|
+
- `supervisor_marker(env, argv)` / `supervisorMarker({env, argv})` reads both forms and answers
|
|
94
|
+
`supervised` (with the manager), `manual` or `conflict`. Only an empty variable counts as no
|
|
95
|
+
marker; a bare `--fabric-supervisor` (followed by nothing, by `--` or by another `--…` flag,
|
|
96
|
+
none of which it consumes) names no manager.
|
|
97
|
+
- Markers that disagree — the variable and the argument with different values, the argument
|
|
98
|
+
twice, or a bare or empty argument beside the variable — exit 75 at once, before the lock and
|
|
99
|
+
whether or not it is held, naming both markers.
|
|
100
|
+
- A service's own argument parser accepts the flag in both spellings and ignores it: in Python,
|
|
101
|
+
`add_supervisor_argument(parser)` (argparse otherwise exits 2 on an unknown flag); the sample
|
|
102
|
+
service adds it to the parser and to each command.
|
|
103
|
+
- The kits are held to the contract's `fixtures/vectors/service-supervisor.json`, and their
|
|
104
|
+
starts against a held lock are recorded and read as `FAC-SEM-078` reads them
|
|
105
|
+
(`test/*supervisors*`).
|
|
82
106
|
|
|
83
107
|
## Directories
|
|
84
108
|
|
|
@@ -151,7 +175,7 @@ control character (a line break would end a unit line early).
|
|
|
151
175
|
**Linux — a systemd user unit.** `systemd_unit(unit, argv, working_directory=…)` /
|
|
152
176
|
`systemdUnit(unit, argv, {workingDirectory})` writes `Restart=always`, `RestartSec=10`,
|
|
153
177
|
`TimeoutStopSec` above the drain (15 s default), `KillMode=mixed`, `WantedBy=default.target`
|
|
154
|
-
and `FABRIC_SERVICE_SUPERVISOR=systemd
|
|
178
|
+
and `FABRIC_SERVICE_SUPERVISOR=systemd` (always, whatever the caller passed), quoting every argument (`%` → `%%`, `$` → `$$`).
|
|
155
179
|
`WorkingDirectory=` is written unquoted: systemd reads it as the rest of the line, so quotes would
|
|
156
180
|
become part of the path and the unit would be refused (`systemd-analyze verify` checks it in CI). The
|
|
157
181
|
descriptor says `"lifecycle": {"manager": "systemd", "unit": "<id>.<instance>.service"}`.
|
|
@@ -179,9 +203,10 @@ CI job has the real `schtasks` create, read back and delete such a task. The des
|
|
|
179
203
|
| stop, keep off | `schtasks /End /TN <task>`, then `schtasks /Change /TN <task> /DISABLE` |
|
|
180
204
|
| uninstall | `task_uninstall` / `taskUninstall`: `/End`, then `/Delete /F` |
|
|
181
205
|
|
|
182
|
-
A task cannot set an environment variable, so
|
|
183
|
-
|
|
184
|
-
|
|
206
|
+
A task cannot set an environment variable, so `task_xml` / `taskXml` write the marker as an
|
|
207
|
+
argument, `--fabric-supervisor task-scheduler`, before any `--`: a copy the Task Scheduler starts
|
|
208
|
+
backs off in-process like one under launchd or systemd. `IgnoreNew` keeps the scheduler from
|
|
209
|
+
starting a second copy.
|
|
185
210
|
|
|
186
211
|
**One copy on each system.** The Python kit takes `flock` (Linux) or a locked byte
|
|
187
212
|
(Windows); the Node kit cannot, so it holds a name instead — an abstract unix socket on Linux,
|
|
@@ -192,7 +217,14 @@ holds the same name beside its file lock, so the two kits exclude each other eve
|
|
|
192
217
|
|
|
193
218
|
**Token files on Windows.** The privacy of `service.token` is its ACL (service.md *Windows
|
|
194
219
|
token files*): the kits write a protected list — the user, SYSTEM and Administrators, set before the
|
|
195
|
-
token's bytes go in, any entry already there dropped
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
220
|
+
token's bytes go in, any entry already there dropped. On read, `windows_token_acl_problem` /
|
|
221
|
+
`windowsTokenAclProblem` decide over what was read — the file's flags, its owner SID and each ACE
|
|
222
|
+
as `{type, sid, mask}` (DEC-0057, `FAC-SEM-079`, held to the contract's
|
|
223
|
+
`fixtures/vectors/windows-token.json`): a reparse point, a directory, a real path outside the
|
|
224
|
+
profile, another owner, an allow ACE with a non-zero mask for any other SID, an ACE of another type
|
|
225
|
+
than allow or deny (an object or callback ACE), or anything unreadable is refused, naming the SID;
|
|
226
|
+
deny ACEs and an allow with an empty mask grant nothing; SIDs compare case-insensitively. The Python
|
|
227
|
+
kit reads the ACEs from the file's SDDL (`acl_from_sddl`); the Node kit reads them with Windows
|
|
228
|
+
PowerShell 5.1 (.NET's raw descriptor, no modules), converting .NET's signed mask to the unsigned
|
|
229
|
+
one, and writes the list with `icacls`; the path goes through the environment, never a command line.
|
|
230
|
+
An inherit-only ACE applies to children, not to the file, and is not read.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# fabric-service/0.1 — wire reference
|
|
2
2
|
|
|
3
|
-
Pinned to `fabric-agent-contract` commit `
|
|
3
|
+
Pinned to `fabric-agent-contract` commit `fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0`
|
|
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
6
|
delegation and the operator session's lifetime DEC-0039; the meter's call window DEC-0041; session handoff DEC-0042;
|
|
7
7
|
canonical forms DEC-0043; `degraded[].setup` and `run.mcp.stdio.scope` DEC-0044; delegation sealed and trust tiers
|
|
8
|
-
DEC-0045; runner and model profiles DEC-0046
|
|
8
|
+
DEC-0045; runner and model profiles DEC-0046; the estate record DEC-0055; one copy under any supervisor and its marker,
|
|
9
|
+
the Windows token-file reader DEC-0057; the hub key the estate certifies DEC-0060; signing credentials DEC-0063; the
|
|
10
|
+
estate record's 60 s skew DEC-0066). The contract's schemas are normative;
|
|
9
11
|
this page is the working summary. Extension key:
|
|
10
12
|
`https://fabric.passioncode.ai/agent-contract/extensions/service/0.1`.
|
|
11
13
|
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py
CHANGED
|
@@ -172,8 +172,11 @@ class Probe:
|
|
|
172
172
|
self.add("descriptor.valid", "FAIL" if problems else "PASS", "; ".join(problems) or str(self.path))
|
|
173
173
|
if fs.WINDOWS:
|
|
174
174
|
# DEC-0032: on Windows the file's ACL is its privacy.
|
|
175
|
-
owner,
|
|
176
|
-
|
|
175
|
+
owner, aces = fs.windows_acl(self.path)
|
|
176
|
+
info = os.lstat(self.path)
|
|
177
|
+
problem = fs.windows_token_acl_problem({"isRegularFile": stat.S_ISREG(info.st_mode), "isReparsePoint": stat.S_ISLNK(info.st_mode),
|
|
178
|
+
"realPathInProfile": True, "ownerSid": owner, "aces": aces}, fs.windows_user_sid())
|
|
179
|
+
problem = problem and problem["message"]
|
|
177
180
|
self.add("descriptor.private", "FAIL" if problem else "PASS", problem or "owner-only ACL")
|
|
178
181
|
else:
|
|
179
182
|
mode = stat.S_IMODE(os.stat(self.path).st_mode)
|