@passioncode-ai/fabric-agent-adapter 0.39.0 → 0.40.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +126 -1
  2. package/README.md +25 -17
  3. package/bin/fabric-agent-adapter.js +6 -6
  4. package/package.json +1 -1
  5. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  6. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +13 -13
  7. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +1 -1
  8. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +4 -4
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +56 -45
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/demo.html +1 -1
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +3 -3
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md +64 -0
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/config.example.json +15 -0
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/knowledge.example.json +13 -0
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/support_agent.py +264 -0
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +12 -12
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/connectors.md +93 -0
  21. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +4 -4
  22. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +1 -1
  23. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +4 -4
  24. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +13 -11
  25. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/estate-record.md +11 -5
  26. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/events-and-notifications.md +6 -6
  27. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +8 -6
  28. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +128 -0
  29. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +26 -26
  30. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +1 -1
  31. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +3 -2
  32. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/profiles.md +10 -10
  33. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +13 -13
  34. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +4 -4
  35. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/settings-backups.md +3 -3
  36. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +5 -5
  37. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/usage.md +7 -4
  38. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +11 -209
  39. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py +204 -0
  40. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +1 -1
  41. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-auth.mjs +286 -0
  42. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-backups.mjs +327 -0
  43. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-base.mjs +47 -0
  44. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-fixture.mjs +79 -0
  45. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-session.mjs +840 -0
  46. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-shapes.mjs +340 -0
  47. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +42 -1237
  48. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ceremonies.mjs +1 -16
  49. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-crypto.mjs +41 -0
  50. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +15 -46
  51. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +387 -0
  52. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +8 -67
  53. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-events.mjs +52 -0
  54. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +231 -0
  55. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +2 -2
  56. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-jsvalue.mjs +67 -0
  57. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +202 -0
  58. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-logs.mjs +136 -0
  59. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-openrouter.mjs +335 -0
  60. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +3 -13
  61. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-paths.mjs +69 -0
  62. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-platform.mjs +164 -0
  63. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-profiles.mjs +1 -32
  64. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +122 -0
  65. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +177 -2521
  66. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-share.mjs +1 -8
  67. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +400 -0
  68. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-time.mjs +46 -0
  69. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-usage.mjs +458 -0
  70. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_auth.py +402 -0
  71. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_backups.py +399 -0
  72. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_base.py +78 -0
  73. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +64 -1398
  74. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_fixture.py +116 -0
  75. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py +902 -0
  76. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_shapes.py +457 -0
  77. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ceremonies.py +36 -38
  78. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_crypto.py +289 -0
  79. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +16 -181
  80. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +586 -0
  81. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +39 -400
  82. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_events.py +137 -0
  83. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +402 -0
  84. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +1 -6
  85. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py +310 -0
  86. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_kit.py +243 -0
  87. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +308 -0
  88. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_logs.py +202 -0
  89. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_openrouter.py +431 -0
  90. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +22 -44
  91. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_paths.py +102 -0
  92. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py +338 -0
  93. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_profiles.py +31 -38
  94. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +173 -0
  95. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +298 -3430
  96. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_share.py +8 -8
  97. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +412 -0
  98. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_time.py +120 -0
  99. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_usage.py +697 -0
  100. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +1526 -0
  101. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +1 -1
  102. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +33 -33
  103. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +1 -1
  104. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/models-and-providers.md +3 -0
  105. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/resilience-and-autonomy.md +27 -27
  106. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +31 -31
  107. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +9 -9
  108. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +8 -8
  109. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +116 -1392
  110. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_cli.py +270 -0
  111. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +508 -0
  112. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_hosts.py +265 -0
  113. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_mail.py +155 -0
  114. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_mcp.py +335 -0
  115. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/host_hooks.py +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,129 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.40.0 - 2026-10-21
4
+
5
+ The kits as production modules (FAA-65). Every name a kit module made public at 0.39.1 is still there; a service that
6
+ copies the kit now installs it with `fabric_kit.py install` (one file is no longer enough, see below).
7
+
8
+ ### Added
9
+
10
+ - **A shared core, once per language** (layer L0 and L1): `fabric_jsvalue` / `fabric-jsvalue.mjs` (JavaScript's view
11
+ of JSON values: `show`, `js_to_number`, `same`, `json_equal`, `jcs` and the rest), `fabric_time` / `fabric-time.mjs`
12
+ (strict RFC 3339, UTC days, formatting, day windows, an injectable clock: the public dates API, on shared cases) and
13
+ `fabric_crypto` / `fabric-crypto.mjs` (Ed25519 and P-256 checks, small-order keys, base64url, sha256). They used to
14
+ live, twice, inside the estate and delegation readers; every reader now imports them.
15
+ - **The kit is a manifest-listed set, installable as one.** `kit.json` lists every module in dependency order, with the
16
+ kit modules it imports, its sha256 and the sha256 of every release since 0.8.0. `fabric_kit.py install <dir>`
17
+ copies a module's closure (data files included); `status <dir>` says `current`, `older` (with its release) or
18
+ `modified`, and names a module a copy imports but lacks. SKILL.md said the kit was "one self-contained file"; it was
19
+ not, and a one-file copy of `fabric_service.py` failed in `usage_findings`.
20
+ - **Connectors** (layer L4, both languages, shared cases): `fabric_http` (one deadline across attempts, bounded
21
+ retries with jittered backoff only when repeating is safe, `Retry-After` up to a cap, a response size cap, redirects
22
+ answered and never followed, plain http refused off loopback, redacted URLs in errors) and `fabric_openrouter` (the
23
+ agent's own key from a named environment variable, a spend ceiling checked before every attempt at the worst case
24
+ with calls in flight reserved, one usage receipt per answered call, empty, `length`, `error` and filtered answers
25
+ never returned as success, a fallback of another vendor required, 401/402/403 stop at once, attribution off by
26
+ default). References: `kit-modules.md`, `connectors.md`.
27
+ - **A support-agent recipe** (`building-fabric-services/recipes/support-agent/`): answers a question from a knowledge
28
+ file through `fabric_openrouter`, accepts a reply only when code proves it (citations exist and were given, no em
29
+ dash or substitute, the question's script, a length limit), otherwise hands it to a person with the failed checks
30
+ named; idempotent per message id. `test/validate.py` lets a recipe import the kit modules `kit.json` lists.
31
+ - **Layering held by tests**: a module imports only modules listed before it (a planted cycle is caught), none is over
32
+ 1000 lines across every skill's scripts, the core is defined once, every module is in the module map, and the
33
+ 0.39.1 public API of both facades is a snapshot test.
34
+
35
+ ### Changed
36
+
37
+ - `fabric_service` / `fabric-service.mjs` and `fabric_board` / `fabric-board.mjs` are facades over modules split by
38
+ responsibility (base, platform, paths, protocols, lock, usage, backups, descriptor, auth, events, logs, supervisors;
39
+ board shapes, session, fixture). The probe's rules moved to `check_service_rules.py`. In working-with-fabric,
40
+ `fabric_session.py` is a facade over `fabric_session_{env,mcp,mail,hosts,cli}.py`; the hooks, the worker and
41
+ `install-host-hooks` still run the facade.
42
+ - No import cycle is left: `fabric_estate` no longer imports `fabric_delegation`, in both languages.
43
+ - A Node service that imported a module-private helper of `fabric-service.mjs` or `fabric-board.mjs` (not exported at
44
+ 0.39.1, so outside the snapshot) imports it from the module that holds it now.
45
+ - The probe runs the board responder's self-check in a clean Python (`-E -s`, its own working directory), so it reads
46
+ the kit it names and not a copy already imported.
47
+
48
+ ### Fixed
49
+
50
+ - **Found by the release review (three blind readings) and fixed before release:** the OpenRouter ceiling counted
51
+ only the messages, so a large `tools` list could pass it (the worst case now bounds the messages and every param;
52
+ `models`, `route`, `plugins` and `web_search_options` are refused); an attempt that may have been billed without an
53
+ answer to read (a timeout, a 200 over the size cap or not JSON) left no receipt (it now records one with no tokens
54
+ and no cost, counted at the worst case); the Python transport could overrun its deadline on a slowly trickled body
55
+ (it reads in chunks against one deadline); the twins differed on a lone surrogate, NaN in a body, a transport bug and
56
+ `http://127.1` (both now behave the same, on shared cases); `fabric_service.py` could not be loaded by its path from
57
+ another folder (every kit module now puts its own folder on `sys.path`, tested from `/`); `fabric_kit.py status`
58
+ judged an older copy by the current release's imports and named only direct ones (it now reads each copy's own
59
+ imports and follows the closure); an unknown `--module` is a usage error (exit 2); the facade keeps `_number`,
60
+ `_DAY_MS` and `_utc_date_ms`; `install-host-hooks` requires the session helper's new modules; the recipe hands off a
61
+ message holding bytes a terminal could not decode instead of exiting, and its dash check also catches U+2012 and
62
+ U+2015.
63
+ - **Found by the second review round and fixed:** a connection cut after a call may have been billed left no receipt
64
+ (every connection error now records an unmeasured one); `max_completion_tokens` and `n` could raise the output past
65
+ the bound (refused); an unmeasured call was counted at the current call's worst case (now at its own, while the
66
+ client runs); Node read a blank or hex price as a number (both twins now read a plain decimal or a number only);
67
+ Python's deadline started after the headers (it now covers them); `fabric_kit.py status` raised on a copy it could
68
+ not parse (it reports it `modified`) and now names a missing module's data files; `fabric_http` writes a JSON body
69
+ byte for byte as `JSON.stringify` (numbers and key order too, through the core's `json_stringify`); loopback edge
70
+ forms agree in both twins; the recipe's dash check covers U+2E3A, U+2E3B, U+FE58 and no-break spaces, and no longer
71
+ flags `1 - 2`.
72
+ - **Found by the third review round and fixed:** an answer with no usage was counted at the next call's worst case
73
+ (now at its own); image, audio and file parts could be sent past the bound (only text content is sent); Python
74
+ raised outside `OpenRouterError` and kept no receipt on a 400-digit count or cost or JSON nested too deep (both read
75
+ as unmeasured now); Python's deadline could be held by trickled headers (a watchdog shuts the socket at the
76
+ deadline); `Response.json()` reads a byte order mark and refuses `NaN` as `JSON.parse` does; a `Retry-After` year
77
+ before 1000 is no date in either twin.
78
+ - **A usage receipt's project id is checked the same way in both kits.** `fabric_service.py` defined its URI pattern
79
+ twice and the second won: Python accepted `project_id="urn:"` where Node refused it. Now one pattern per module, and
80
+ both kits refuse it (a test in each).
81
+
82
+ ## 0.39.1 - 2026-10-21
83
+
84
+ Fixes from two rounds of blind review of 0.39.0 (FAA-64).
85
+
86
+ ### Fixed
87
+
88
+ - **The probe no longer crashes on a usage report it is checking.** `check_service.py` compared `unpricedCalls` and
89
+ `unmeasuredCalls` raw, so `null` or a string raised `TypeError`, and a 400-digit cost raised `OverflowError`; either
90
+ stopped the whole probe before its other rules ran. Its FAC-SEM-025 arithmetic is now the kit's `usage_findings`, one
91
+ implementation held to the contract's vectors.
92
+ - **The Python and Node kits answer FAC-SEM-025 as the contract does, message for message.** Both read each count as
93
+ the contract's `toNumber(x ?? 0)`, each date and project id with `show`, a cost as JavaScript holds the number (an
94
+ integer beyond a double is Infinity, which is never close to a sum), and a whole number written `5.0` as a count.
95
+ Python compared raw values and read `5.0` as 0; Node threw on an object such as `{"toString": 1}` in a count, a date
96
+ or a project id. The vectors now carry each finding's message and both kits compare it: 183 new report cases (208)
97
+ set every count and the cost of a day and of its first model to eleven values the schema refuses, plus three days
98
+ with no model rows and four dates and ids that are objects or numbers; eight new cases are the report's JSON text,
99
+ which each kit parses itself (a 400-digit integer, `1e400`, `2^53 + 1`, `5.0`). The field list is the contract's at this pin,
100
+ written in the generator.
101
+ - **Messages a person reads carry no em dash**: the probe, the dashboard-kit notice, the board's retry hint and the
102
+ package refusal (Python and Node alike), the installer and the `npx` CLI, the sample service's page, the session
103
+ hooks' unread and status lines (`2 unread on the project board: com.list`) and the dashboard kit's Fabric button
104
+ (`Fabric is not installed. Get it at passioncode.ai/fabric`; kit **1.1.1**, so a service's kit copy is offered the
105
+ upgrade). The live documentation, evals and the kit's demo page were rewritten the same way.
106
+
107
+ ### Added
108
+
109
+ - Tests for the producer side of DEC-0091 in both kits: receipts with `tokens_measured=False` through
110
+ `usage_report`, the day and model `unmeasuredCalls`, none on `byProject`, the probe clean, and the refusal of a
111
+ non-boolean flag.
112
+ - Evals: the spend scenario expects unknown tokens in `unmeasuredCalls`; a new scenario covers a partner's package
113
+ and calls (DEC-0090).
114
+ - `interop.md` and `usage.md` say a job whose usage is sent as `null` or `partial` is recorded with
115
+ `tokens_measured=False`; `estate-record.md` says a service updates its copied kit before a revision carries
116
+ `publisherScopes` (an older copy trusts a partner's key in every context); FAC-SEM-122 in its header and DEC-0091 in
117
+ protocol.md's FAC-SEM-025 row.
118
+ - `test/validate.py` fails on U+2014 in the live documentation, the evals, the installer, the CLI and the kit's demo,
119
+ and when README states which version a checkout is or which release is the latest (it said 0.21.0 until now); both
120
+ checks have tests. The compiled-revision tests name the two contract revisions they need when they skip.
121
+
122
+ ### Raised with the contract (not changed here)
123
+
124
+ - `chainOf` names a `{sub, partner}` node by its `org:` id, and job ownership and idempotency keys do not include the
125
+ partner. The kits follow `c55f2d5` until the contract decides (board thread `6e66a023`, FAA-64).
126
+
3
127
  ## 0.39.0 - 2026-10-20
4
128
 
5
129
  ### Changed
@@ -12,7 +136,8 @@
12
136
  - **Unmeasured tokens are named** (DEC-0091, contract CT-62). `make_usage_receipt(..., tokens_measured=False)` /
13
137
  `makeUsageReceipt(..., { tokensMeasured: false })` writes `tokensMeasured: false`; the report counts such calls in
14
138
  `unmeasuredCalls` on the day and the model row, and FAC-SEM-025 in both kits and `check_service.py` refuses a row
15
- with more unmeasured calls than calls or a day whose count is not its models' sum. Three new usage vectors (25).
139
+ with more unmeasured calls than calls or a day whose count is not its models' sum. Four new usage vectors (25; this
140
+ line said three until 0.39.1).
16
141
  - **A partner in the delegation chain** (DEC-0090, contract CT-58). Both verifiers take `{partner: "org:<id>"}` as the
17
142
  innermost actor under at least one agent: it counts toward the depth limit and ends the chain, and the checked chain
18
143
  lists it by its `org:` id. Outermost, with an `act` beneath, `personal` or an `ORG:` prefix is `malformed-chain`.
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 — four Agent Skills,
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.
@@ -51,12 +51,18 @@ is the board-first workflow.
51
51
 
52
52
  `building-fabric-services` makes an agent a long-lived local service with a dashboard
53
53
  that is always alive, runs as one copy, keeps its state through a reinstall and appears
54
- in Fabric Dashboards by itself — the `fabric-service/0.1` extension. It also makes an **online** agent
55
- or dashboard — an `https` origin on a platform — a Fabric service (the remote placement, DEC-0019): the same
54
+ in Fabric Dashboards by itself: the `fabric-service/0.1` extension. It also makes an **online** agent
55
+ or dashboard (an `https` origin on a platform) a Fabric service (the remote placement, DEC-0019): the same
56
56
  four routes behind the token, a `__Host-` session cookie, and one descriptor on the operator's computer;
57
- `scripts/sample-remote-service.mjs` is the complete example. It ships Python and
58
- Node reference kits (`scripts/fabric_service.py`, `scripts/fabric-service.mjs`), a
59
- complete `scripts/sample_service.py`, and `scripts/check_service.py`, a live probe. A service that answers
57
+ `scripts/sample-remote-service.mjs` is the complete example. It ships the service kit in Python and
58
+ Node: layered modules listed in `scripts/kit.json` behind the `fabric_service` / `fabric-service.mjs` facades,
59
+ installed into a service with `scripts/fabric_kit.py install` and checked with `fabric_kit.py status`
60
+ ([kit modules](plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md), including
61
+ the dates API); connectors for outbound HTTP and OpenRouter (`fabric_http`, `fabric_openrouter`: one deadline, safe
62
+ retries, the agent's own key, a spend ceiling before every attempt, usage receipts, a fallback model;
63
+ [connectors](plugins/fabric-agent-adapter/skills/building-fabric-services/references/connectors.md)); a ready
64
+ [support-agent recipe](plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md);
65
+ a complete `scripts/sample_service.py`; and `scripts/check_service.py`, a live probe. A service that answers
60
66
  requests other Projects post to its Project on Fabric's project board uses the board responder
61
67
  (`scripts/fabric_hub.py` and `scripts/fabric_board.py`, Node `fabric-hub.mjs` and `fabric-board.mjs`): the
62
68
  `board.respond` grant, enroll, claim, accept the exact digest, complete, a checkpoint before every step, and restarts
@@ -68,8 +74,8 @@ python3 plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/che
68
74
 
69
75
  The dashboard itself is built from the **dashboard kit** (`assets/dashboard-kit/`, `fabric-dashboard/0.1`,
70
76
  contract DEC-0036): one stylesheet and one script that keep the page usable from 360 CSS px inside a host
71
- pane beside the agent console — navigation that folds into a More menu, wide tables in their own scroll
72
- box, sticky chrome at most 120 px — with seven WCAG AA themes (light and dark) that follow the host's
77
+ pane beside the agent console (navigation that folds into a More menu, wide tables in their own scroll
78
+ box, sticky chrome at most 120 px) with seven WCAG AA themes (light and dark) that follow the host's
73
79
  `fabric_appearance` cookie. `scripts/dashboard_kit.py install|status` copies and checks it,
74
80
  `scripts/check_dashboard_layout.mjs` measures a rendered page in WebKit at 360, 480, 768 and 1280 px
75
81
  (Playwright; `NOT_RUN` without it), and the probe's `dashboard.declared` checks the declaration. The
@@ -117,7 +123,7 @@ yet ship the host registry/runtime needed to connect and authorize a live provid
117
123
  ### Install
118
124
 
119
125
  With the [PassionCode.ai launcher](https://github.com/passioncode-ai/passioncode) the adapter
120
- comes with every other PassionCode.ai skill — `npx @passioncode-ai/passioncode@latest update`,
126
+ comes with every other PassionCode.ai skill: `npx @passioncode-ai/passioncode@latest update`,
121
127
  then restart your agents. Alone, without any account:
122
128
 
123
129
  ```bash
@@ -175,8 +181,8 @@ kill %1
175
181
 
176
182
  Verified 2026-10-01 from the published npm package 0.5.4 (`npx` into a throwaway hub, `KIT`
177
183
  pointing at the installed skill) with Claude Code 2.1.286: the probe reported 27 rules, 0 FAIL;
178
- the CLI connected to the sample over streamable HTTP, called `sample.echo` and printed `ping`. The probe prints one line per rule —
179
- `PASS`, `FAIL` or `NOT_RUN` with its evidence — and exits 1 on any `FAIL`; run it against your
184
+ the CLI connected to the sample over streamable HTTP, called `sample.echo` and printed `ping`. The probe prints one line per rule
185
+ (`PASS`, `FAIL` or `NOT_RUN` with its evidence) and exits 1 on any `FAIL`; run it against your
180
186
  own service by its id once its installer has written the descriptor.
181
187
  `FABRIC_REAL_CLIENT=1 python3 -m unittest discover -s test -p test_real_client.py` repeats the connection check
182
188
  (every sample tool listed, no model call) in the test suite.
@@ -264,8 +270,8 @@ The default pin for new bundles is [`fabric-contract.lock.json`](fabric-contract
264
270
  - version: `0.1.0`
265
271
  - commit: `c55f2d5a11c9a0197e958e87212fca7ae1154769`
266
272
 
267
- Every other mention of the default contract revision — this section, the skills' metadata, the
268
- skill card, `adapt_project.py` — must equal it; `python3 test/validate.py` fails a tree
273
+ Every other mention of the default contract revision (this section, the skills' metadata, the
274
+ skill card, `adapt_project.py`) must equal it; `python3 test/validate.py` fails a tree
269
275
  where one does not. The sole live legacy exception is the immutable
270
276
  `SUPPORTED_CONTRACT_COMMITS` declaration in the scaffolder: previously issued bundles
271
277
  keep their selected legacy lock and require that exact clean contract checkout. The
@@ -288,14 +294,16 @@ FABRIC_CONTRACT_OLD=/path/to/legacy-contract FABRIC_CONTRACT_NEW=/path/to/curren
288
294
  python3 -m unittest discover -s test -p test_contract_revisions.py -v
289
295
  ```
290
296
 
291
- Without both environment variables, those tests explicitly skip as `NOT_RUN`.
292
- This source checkout is 0.21.0. 0.20.0 is the latest published GitHub/npm release (2026-10-12; 0.7.0 and 0.11.0
293
- were never released); 0.21.0 is published by its `v0.21.0` tag. Source delivery does not update installed skills or live sessions.
297
+ `FABRIC_CONTRACT_OLD` is a checkout of the legacy fixtures' revision (`OLD` in `test/test_contract_revisions.py`) and
298
+ `FABRIC_CONTRACT_NEW` one of the pin; each needs `pnpm install --frozen-lockfile` in its own folder (pnpm refuses a
299
+ symlinked `node_modules`). Without both environment variables, those tests explicitly skip as `NOT_RUN`, naming the
300
+ two revisions. What each version changed and when it was released is in [CHANGELOG.md](CHANGELOG.md). Source delivery
301
+ does not update installed skills or live sessions.
294
302
 
295
303
  ## License
296
304
 
297
305
  Open source under the [GNU AGPL-3.0](LICENSE). A [commercial license](COMMERCIAL-LICENSE.md) is
298
- available for use that does not meet the AGPL's terms — [passioncode.ai/business](https://passioncode.ai/business/).
306
+ available for use that does not meet the AGPL's terms: [passioncode.ai/business](https://passioncode.ai/business/).
299
307
  Versions before 0.5.3 were released under PolyForm Noncommercial or Internal Use (v0.4.3 to
300
308
  v0.5.2) and MIT (v0.4.2 and earlier); each keeps the licence it was released under.
301
309
  Contributions are accepted under [CLA.md](CLA.md) ([CONTRIBUTING.md](CONTRIBUTING.md)).
@@ -26,7 +26,7 @@ Usage:
26
26
  npx @passioncode-ai/fabric-agent-adapter [--force]
27
27
  install every skill into the agents hub ~/.agents/skills
28
28
  npx @passioncode-ai/fabric-agent-adapter --target claude [--force]
29
- plain copy into ~/.claude/skills — refused while the plugin is installed
29
+ plain copy into ~/.claude/skills (refused while the plugin is installed)
30
30
  npx @passioncode-ai/fabric-agent-adapter --prune-shadow
31
31
  remove plain ~/.claude/skills copies that shadow the installed plugin
32
32
  npx @passioncode-ai/fabric-agent-adapter --help
@@ -124,7 +124,7 @@ function main(argv) {
124
124
 
125
125
  const { skillRoot, names } = skillNames();
126
126
  if (!names.length) {
127
- console.error(`error: no skills found under ${skillRoot} — corrupted package?`);
127
+ console.error(`error: no skills found under ${skillRoot}; corrupted package?`);
128
128
  return 1;
129
129
  }
130
130
  const home = os.homedir();
@@ -132,7 +132,7 @@ function main(argv) {
132
132
 
133
133
  if (prune) {
134
134
  if (!hasPlugin) {
135
- console.error(`error: the ${PLUGIN_ID} plugin is not installed, so a copy in ~/.claude/skills is not a shadow — nothing removed.`);
135
+ console.error(`error: the ${PLUGIN_ID} plugin is not installed, so a copy in ~/.claude/skills is not a shadow; nothing removed.`);
136
136
  return 1;
137
137
  }
138
138
  pruneShadows(home, names);
@@ -151,8 +151,8 @@ function main(argv) {
151
151
  // One owner per artefact on disk: a plain copy over someone else's link freezes the skill
152
152
  // at this version, and its owner stops updating it. --force does not override this.
153
153
  console.log(owner === 'launcher'
154
- ? `skip: ${name} at ${dest} is managed by the PassionCode launcher — update it with: npx @passioncode-ai/passioncode@latest update`
155
- : `skip: ${name} at ${dest} is a link managed elsewhere — remove the link first to install a copy here`);
154
+ ? `skip: ${name} at ${dest} is managed by the PassionCode launcher; update it with: npx @passioncode-ai/passioncode@latest update`
155
+ : `skip: ${name} at ${dest} is a link managed elsewhere; remove the link first to install a copy here`);
156
156
  continue;
157
157
  }
158
158
  if (fs.existsSync(dest) && !force) {
@@ -166,7 +166,7 @@ function main(argv) {
166
166
  if (target === 'agents' && !hasPlugin) {
167
167
  console.log(`Claude Code reads plugins, not the hub:\n claude plugin marketplace add ${REPO} && claude plugin install ${PLUGIN_ID}`);
168
168
  }
169
- console.log('Restart your agent — skills load at session start.');
169
+ console.log('Restart your agent: skills load at session start.');
170
170
  return 0;
171
171
  }
172
172
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@passioncode-ai/fabric-agent-adapter",
3
- "version": "0.39.0",
3
+ "version": "0.40.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'"
@@ -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; 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.39.0",
6
+ "version": "0.40.0",
7
7
  "author": {
8
8
  "name": "PassionCode.ai",
9
9
  "url": "https://passioncode.ai/"
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: adapting-projects-to-fabric
3
- description: Use when adapting an existing agent, MCP server, A2A peer, HTTP service, or terminal CLI to the Fabric Agent Contract—choosing MCP/A2A/local-runner, scaffolding a provider bundle, or checking Fabric compatibility; also for «подключить проект к Fabric» or «сделать агента совместимым с Fabric». NOT for building the Fabric host/orchestrator, configuring an MCP client, or a brand-new agent — that is creating-fabric-agents.
3
+ description: Use when adapting an existing agent, MCP server, A2A peer, HTTP service, or terminal CLI to the Fabric Agent Contract (choosing MCP/A2A/local-runner, scaffolding a provider bundle, or checking Fabric compatibility); also for «подключить проект к Fabric» or «сделать агента совместимым с Fabric». NOT for building the Fabric host/orchestrator, configuring an MCP client, or a brand-new agent (that is creating-fabric-agents).
4
4
  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.39.0"
8
+ version: "0.40.0"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "c55f2d5a11c9a0197e958e87212fca7ae1154769"
11
11
  ---
@@ -23,9 +23,9 @@ Use this skill to adapt or assess a provider project. Do not use it to:
23
23
  - design the Fabric host, registry, scheduler, admission service, or project binding runtime;
24
24
  - add an MCP server to Claude Code, Codex, or an agent gateway;
25
25
  - answer wire-level MCP or A2A questions (transports, sessions, auth handshakes, task
26
- states on the wire) — that is `agent-interop` (agent-stack); the pinned contract stays
26
+ states on the wire): that is `agent-interop` (agent-stack); the pinned contract stays
27
27
  normative for what Fabric requires;
28
- - design a new agent from scratch — that is the sibling skill creating-fabric-agents;
28
+ - design a new agent from scratch: that is the sibling skill creating-fabric-agents;
29
29
  - claim admission merely because generated files or a valid manifest exist.
30
30
 
31
31
  If the project has only a browser interface and no stable API, MCP/A2A surface, or CLI,
@@ -133,14 +133,14 @@ Preserve the chosen ownership boundary:
133
133
  heartbeat, and partial results without relying on ambient accounts.
134
134
 
135
135
  Keep model selection and provider-internal reasoning outside the Fabric contract. Expose
136
- typed outcomes, evidence, artifacts, and protocol-visible state—not chain-of-thought.
136
+ typed outcomes, evidence, artifacts, and protocol-visible state, not chain-of-thought.
137
137
  Treat all provider output as untrusted until schemas and semantic assertions pass.
138
138
 
139
139
  ### 4b. Announce an agent that is not a service
140
140
 
141
141
  An agent Fabric reaches as a CLI or a stdio MCP server gets a provider entry, written by
142
142
  its installer with [`scripts/fabric_provider.py`](scripts/fabric_provider.py) and removed
143
- by its uninstaller — argv arrays only, env values as `secret-ref:` references, never the
143
+ by its uninstaller: argv arrays only, env values as `secret-ref:` references, never the
144
144
  id of an existing service, and a `providerId` equal to the manifest's `provider.id`. Load [provider entries](references/provider-entry.md). An
145
145
  agent that runs as a service uses a descriptor instead (`building-fabric-services`).
146
146
 
@@ -174,8 +174,8 @@ python3 <skill-dir>/scripts/adapt_project.py check <project-root> \
174
174
  ```
175
175
 
176
176
  The local check also refuses two lifecycle faults (LC-19, LC-21): a Claude Code plugin in
177
- the project that declares a stdio MCP server — it starts in every session that enables the
178
- plugin; serve it over HTTP from one resident process or register it at project scope — and a
177
+ the project that declares a stdio MCP server (it starts in every session that enables the
178
+ plugin; serve it over HTTP from one resident process or register it at project scope), and a
179
179
  credential in a launch argument or a URL query, where every process and every log can read it.
180
180
  Fix both at their cause; never weaken the check.
181
181
 
@@ -214,11 +214,11 @@ operator's four steps:
214
214
  4. type the code it shows in the chat with the bot.
215
215
 
216
216
  In a group shared with other bots the channel follows OC-14…OC-17 (DEC-0035): it stays silent
217
- unless addressed — `/command@ThisBot`, a reply to its own message or a press of its own button; a
218
- bare `/command` in a group is not addressed — and a channel nobody receives on is `degraded`
217
+ unless addressed (`/command@ThisBot`, a reply to its own message or a press of its own button; a
218
+ bare `/command` in a group is not addressed), and a channel nobody receives on is `degraded`
219
219
  (`receiver-missing`). Say so in the proposal when the operator means to bind a shared group.
220
220
 
221
- Record the answer — `accepted`, `declined` or `later` — in the agent's state and the
221
+ Record the answer (`accepted`, `declined` or `later`) in the agent's state and the
222
222
  conformance report, and do not ask again; an agent that serves `surfaces.operatorChannel` also
223
223
  shows it as `proposal` in its status document. Creating the bot, storing the token and enabling the
224
224
  channel are the operator's action: never create the bot, ask for or store the token's value, or
@@ -246,7 +246,7 @@ first commit:
246
246
  org-index `scripts/check_format.py` reports 0 findings for it before it is called done. **An agent
247
247
  someone builds for themselves is not a PassionCode.ai repository:** its licence is its owner's
248
248
  choice, nothing about it is published or listed by the organization, and none of these files is
249
- required of it — though the verified MCP quick start is still how anyone learns to drive it.
249
+ required of it, though the verified MCP quick start is still how anyone learns to drive it.
250
250
 
251
251
  ## Completion format
252
252
 
@@ -263,7 +263,7 @@ Report:
263
263
  Never summarize the outcome as “Fabric-compatible” unless all required admission gates
264
264
  passed against a real provider and the project binding is valid.
265
265
 
266
- ## Dashboard handoff — also for consumers
266
+ ## Dashboard handoff: also for consumers
267
267
 
268
268
  When handing a registered service dashboard to a person, or writing the generated
269
269
  agent's completion/notification instructions, read and apply
@@ -1,4 +1,4 @@
1
- # Dashboard links — producer and consumer rule
1
+ # Dashboard links: producer and consumer rule
2
2
 
3
3
  Read when an agent creates a dashboard, implements `<tool> dashboard`, or hands
4
4
  an existing Fabric service dashboard to a person. This also applies to generated
@@ -3,7 +3,7 @@
3
3
  Normative source: the Fabric Agent Contract's `docs/specification/provider.md`
4
4
  (`fabric-provider/0.1`, DEC-0016, rulings DEC-0017) at the commit this plugin pins.
5
5
 
6
- An agent Fabric reaches as a CLI or a stdio MCP server — not a long-running service —
6
+ An agent Fabric reaches as a CLI or a stdio MCP server (not a long-running service)
7
7
  is announced by one entry, `providers/<id>.json`, in the same root as the services
8
8
  directory:
9
9
 
@@ -34,17 +34,17 @@ python3 scripts/fabric_provider.py remove example-agent # the uninstaller
34
34
 
35
35
  `--stdio` takes the rest of the line as the argument array; there is no shell string. An entry may carry
36
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
37
+ `session` (a server in every coding session) is refused (FAC-SEM-056, LC-19). The validator accepts the field; the
38
38
  writer does not set it until Fabric reads it. An argument that carries a credential is refused
39
39
  (LC-21, FAC-SEM-057): a key goes in `env` as a `secret-ref:<name>`, never in argv.
40
40
 
41
41
  It refuses, with one sentence that never quotes a value:
42
42
 
43
43
  - a manifest that does not resolve, or whose `provider.id` is not the entry's
44
- `providerId` — the two URIs are compared as URIs (FAC-SEM-014);
44
+ `providerId`: the two URIs are compared as URIs (FAC-SEM-014);
45
45
  - an id that is already a service in `services/` (FAC-SEM-013);
46
46
  - an env value that is not `secret-ref:<name>`, or a reference that has the shape of a
47
- credential itself — a token prefix, a private key, a JWT (FAC-SEM-015: a value is
47
+ credential itself: a token prefix, a private key, a JWT (FAC-SEM-015: a value is
48
48
  checked by its form; name patterns apply to names);
49
49
  - a URL other than `http://127.0.0.1:<port>/mcp`, a manifest path that is not an
50
50
  absolute or `~/` path to `fabric-agent.json`, a shell-string command, unknown fields.