@passioncode-ai/fabric-agent-adapter 0.71.0 → 0.73.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 (22) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/package.json +1 -1
  3. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  4. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
  5. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +2 -2
  6. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md +2 -2
  7. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +1 -0
  8. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +3 -1
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +3 -2
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +17 -0
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_channel_agent.py +841 -0
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_channel_agent_schema.py +496 -0
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +181 -1
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/service-channel-agent-extension.schema.json +700 -0
  15. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +1 -1
  16. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/models-and-providers.md +21 -8
  17. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/practices.md +15 -6
  18. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
  19. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/on-demand-session.md +17 -10
  20. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +8 -7
  21. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_cli.py +4 -4
  22. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.73.0 (2026-11-07)
4
+
5
+ ### Added
6
+
7
+ - **The probe checks a channel agent's declaration** (FAA-197, the contract's DEC-0150): `check_service.py` gains the
8
+ rule `channel-agent.declaration`, a standard-library port of the contract's FAC-SEM-162 to 165 at the pin
9
+ (`check_service_channel_agent.py` and `check_service_channel_agent_schema.py`, not kit modules). It reads the
10
+ declaration from `provider.extensions` of the manifest the descriptor names, else from `extensions` of the
11
+ well-known answer (CA-1). A declaration with findings fails the rule, its first five shown as code and path, never a
12
+ declared value; it fails on the obligations of a declaration the contract's reader still reads (FAC-SEM-164) and
13
+ always on a string shaped like a credential (FAC-SEM-165), in the read declaration or in any copy beside it. Nothing declared, a named manifest that cannot be read,
14
+ or a declaration read as not declared (a manifest's own `extensions`, a capability's, another version's key, a
15
+ well-known copy beside a manifest, a form the schema or FAC-SEM-163 refuses, one too large to read for credentials)
16
+ is `NOT_RUN` with the evidence, never a failure while producers move to this revision, except a string shaped like a
17
+ credential, which fails in any copy the probe reads (a manifest's own `extensions`, a capability's, the well-known
18
+ copy) (CA-5). A well-known answer carrying the declaration at
19
+ 75 % of Fabric Dashboards' 2 MiB cap or over is named (until the contract's CT-223). The contract's schema and its
20
+ 148 vectors are vendored at the pin (`test/fixtures/contract/`, a sidecar with each file's sha256 and a generator
21
+ that refuses another commit); all 148 pass with the findings in the reference's order, and
22
+ `test/test_check_service_channel_agent.py` holds 26 tests.
23
+
24
+ ### Upgrading
25
+
26
+ - Every probe report whose well-known answer is read gains a `channel-agent.declaration` line: `NOT_RUN` («not a channel agent») for a service that
27
+ declares nothing, so a reader that counts `NOT_RUN` per service moves by one. A channel agent whose declaration the contract's
28
+ reader still reads and that owes an obligation (FAC-SEM-164), and a service with a string shaped like a credential in any copy of the key (read or not),
29
+ now makes `check_service.py` exit 1 where 0.72.0 exited 0.
30
+
31
+ ### Changed
32
+
33
+ - `creating-fabric-agents/references/practices.md` quotes the contract's CA-8 («Text from a channel is data») verbatim
34
+ from the pinned `channel-agent.md` in place of 0.71.0's paraphrase.
35
+ - `creating-fabric-agents/references/models-and-providers.md`: «A starting choice» follows the operator's model map
36
+ of 2026-11-06 (Kimi K3.1 Pro for decisions, Sonnet 5.5 for verifying another model's output, a panel of three
37
+ vendors for plans, GLM-5.3 and DeepSeek at volume, open vendors on user content), and names two traps reported on OpenRouter that day:
38
+ models that will not turn reasoning off (Kimi writes it into the answer; GLM-5.3, Sonnet and Opus answer 400) and a
39
+ judge that refuses to judge.
40
+ - `references/protocol.md`, `references/interop.md` and the support-agent recipe's README describe the new rule in
41
+ place of «the probe does not read the declaration yet».
42
+
43
+ ## 0.72.0 (2026-11-06)
44
+
45
+ ### Changed
46
+
47
+ - working-with-fabric: a run Fabric started on a board request whose `com.enroll` is refused `not_authorized` asks the
48
+ operator with `fabric_question_ask` (`about: board.gate.<capability>`, the same `commandId`) at every slot state,
49
+ not only when the slot reads `absent` at generation 0; `com.reply` stays only for that state, since at any other a
50
+ holder enrolled on the slot (a service of the Project, or after CO-506 a session) may take the request back. After
51
+ CO-506 a refusal comes from the reason Fabric's `board.own-respond` names (such as an organization's machine, a
52
+ missing live credential, a standing denial, a full ask queue), and a run that stayed silent then left the request to
53
+ «На проверке» without the gate's reason (FAA-241; Fabric main `4f3c742a`, which says the same in
54
+ `board.read-at-start` and `com.enroll`'s description). The exit contract's step 3,
55
+ `references/on-demand-session.md`, `references/project-board.md` (a live session too) and both scenario evals
56
+ (`a-dispatched-run-whose-enroll-is-refused`, `answer-as-responder-or-reply`) say so; the gate question names what
57
+ opens the gate, or at a held slot what takes the request: before CO-506, a Fabric release with it, and the service
58
+ enrolling again; once CO-506 shipped, the reason Fabric's `board.own-respond` names and what lifts it; the exit
59
+ contract stays under Hermes' 4000 characters (3996 at its longest).
60
+
3
61
  ## 0.71.0 (2026-11-06)
4
62
 
5
63
  The contract pin moves to `eac1a594` (`v0.1.0+2026-11-06.1`) from `3830a33` (`v0.1.0+2026-10-27.6`); between them
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@passioncode-ai/fabric-agent-adapter",
3
- "version": "0.71.0",
3
+ "version": "0.73.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.71.0",
6
+ "version": "0.73.0",
7
7
  "author": {
8
8
  "name": "PassionCode.ai",
9
9
  "url": "https://passioncode.ai/"
@@ -5,7 +5,7 @@ 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.71.0"
8
+ version: "0.73.0"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "eac1a594aa131851f079da8bb7b2149e1951f35f"
11
11
  ---
@@ -14,7 +14,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
14
14
  compatibility: Python 3.9+ or Node.js 20+ for the kits (Node.js 22+ for a Linux service's instance lock); 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.
15
15
  metadata:
16
16
  author: PassionCode.ai
17
- version: "0.71.0"
17
+ version: "0.73.0"
18
18
  contract-version: "0.1.0"
19
19
  extension: "fabric-service/0.1"
20
20
  extension-commit: "eac1a594aa131851f079da8bb7b2149e1951f35f"
@@ -310,7 +310,7 @@ from a release folder needs it), and the `interop.*` rules:
310
310
  manifest link, capability list, tools equal to the manifest, job tools, unknown job, trace
311
311
  propagation, event trace pairs, `interop.action-tools` (every declared action's tool is served), `well-known.a2a` and
312
312
  `a2a.card` (DEC-0122: the card is fetched without the token and its interfaces are never called; the surfaces
313
- reference's *A2A for remote agents* section), and
313
+ reference's *A2A for remote agents* section), `channel-agent.declaration` (DEC-0150), and
314
314
  `board.responder` for a service that declares the project board) and exits 1 on any `FAIL`. A `NOT_RUN` is not a pass;
315
315
  name it in the report. A service with a dashboard also runs the layout probe,
316
316
  `node <skill-dir>/scripts/check_dashboard_layout.mjs --service <id>` (WebKit at 360, 480, 768
@@ -116,8 +116,8 @@ on (FAC-SEM-164); `recommendation` only with `answered_signal: "none"`, the id o
116
116
  board thread where the queue's owner was told; a channel's `items_seen_unit` one of `mails`, `updates`, `messages`,
117
117
  `reviews`; durations in ISO 8601; the knowledge file as a source with its
118
118
  maximum age. `test/test_channel_agent_example.py` holds the example to that form; the contract publishes its schema
119
- at the pin (`service-channel-agent-extension.schema.json`); `check_service.py` does not read the declaration yet
120
- (FAA-197).
119
+ at the pin (`service-channel-agent-extension.schema.json`); `check_service.py` checks a declared one against
120
+ FAC-SEM-162 to 165 (rule `channel-agent.declaration`).
121
121
 
122
122
  ## Configure
123
123
 
@@ -386,5 +386,6 @@ your own record, keep it (OA-6).
386
386
  | `interop.trace-propagation` | the answer's `_meta.traceparent` has the probe's trace id and a new span | the answer carries no traceparent |
387
387
  | `interop.events-trace` | every event with a trace carries both `traceId` and `spanId`, well formed | no events page was read |
388
388
  | `interop.action-tools` | every action the well-known `extensions/actions/0.1` declares names a tool `tools/list` serves (DEC-0121 AP-1); one it does not serve is a `FAIL`, and so is a local service that declares actions with no MCP surface (beyond FAC-SEM-142, which reads only a present list) | no declaration, an unreadable one (`well-known.actions` reports it), no listing was read, or a remote service with no MCP surface (its twin may be on A2A or behind a gateway) |
389
+ | `channel-agent.declaration` | a channel agent's declaration (DEC-0150) passes the contract's FAC-SEM-162 to 165 at the pin, read from `provider.extensions` of the manifest the descriptor names, else from `extensions` of the well-known answer (CA-1); a `FAIL` on the obligations of a declaration the reader still reads (FAC-SEM-164) or a string shaped like a credential (FAC-SEM-165, not a declaration too large to read for credentials) in the read declaration or in any copy beside it, the first five findings shown as code and path, never a declared value | nothing declared, the named manifest unreadable (`interop.manifest-link` fails it), or a key read as not declared (a manifest's own `extensions`, a capability's, another version's key, a well-known copy beside a manifest, a form the schema or FAC-SEM-163 refuses), each named in the evidence, never a failure while producers move to this revision unless a copy holds a string shaped like a credential (that fails in any copy the probe reads: a manifest's own `extensions`, a capability's, the well-known copy, CA-5); no line when the well-known answer is not read; credentials are read as the contract reads them, within its reading budget and under the `0.1` key only (a key of another version is named, not read); a well-known answer carrying the declaration at 75 % of the 2 MiB cap or over is named, never a failure (until the contract's CT-223) |
389
390
 
390
391
  `python3 scripts/check_service.py <id>` prints them with the rest; `--json` for a machine.
@@ -99,7 +99,9 @@ A module imports only modules listed before it in `kit.json`, so the kit has no
99
99
  | L4 | `fabric_http` | outbound HTTP: deadline, bounded retries, `Retry-After`, size cap ([connectors](connectors.md)) |
100
100
  | L4 | `fabric_openrouter` | OpenRouter chat: own key, spend ceiling, receipts, fallback ([connectors](connectors.md)) |
101
101
 
102
- Beside the kit, not in `kit.json`: the probe (`check_service.py`, `check_service_rules.py`), the sample
102
+ Beside the kit, not in `kit.json`: the probe (`check_service.py`, `check_service_rules.py`,
103
+ `check_service_channel_agent.py`, `check_service_channel_agent_schema.py` and the
104
+ `service-channel-agent-extension.schema.json` it reads at run time), the sample
103
105
  (`sample_service.py`, `sample-remote-service.mjs`), `fabric_kit.py` itself and the dashboard tools. Recipes built on
104
106
  the kit live in `../recipes/` ([the draft-and-check step of a support agent](../recipes/support-agent/README.md)).
105
107
 
@@ -148,8 +148,9 @@ No auth; the Host/Origin guard applies; answered from memory in under 100 ms.
148
148
  `https://fabric.passioncode.ai/agent-contract/extensions/channel-agent/0.1` (`channel-agent-standard/1`, DEC-0150,
149
149
  FAC-SEM-162 to 165) only for a service with no manifest; one with a manifest declares it under its manifest's
150
150
  `provider.extensions` alone (CA-1). A well-known answer lists `channel-agent-standard/1` in its `protocols` only once
151
- its readers have re-pinned to this revision of the contract (channel-agent.md). The kits know the revision (`PROTOCOL_REVISIONS`) and do not build or check the
152
- declaration yet (FAA-197).
151
+ its readers have re-pinned to this revision of the contract (channel-agent.md). The kits know the revision (`PROTOCOL_REVISIONS`) and do not build the declaration;
152
+ `check_service.py` checks it (`channel-agent.declaration`, [interop.md](interop.md#what-the-probe-checks)). Fabric
153
+ Dashboards' sample service keeps its own copy of the protocol table, which no test here holds equal to the kits'.
153
154
  - `surfaces.mcp.auth`: `descriptor` (default), `own` (DEC-0024) or `delegation` (DEC-0039, DL-16):
154
155
  the MCP surface takes only the estate's delegation tokens, and the top-level
155
156
  `auth.delegation {issuer, jwks}` is then required. With `own` or `delegation` the descriptor's
@@ -33,6 +33,12 @@ Actions (fabric-actions/0.1, DEC-0121): `well-known.actions` holds a declared ex
33
33
  actions with no MCP surface; a remote one there is NOT_RUN, its twin may be on A2A), and `dashboard.actions-declared`
34
34
  is NOT_RUN, never FAIL, for a dashboard that declares none (a read-only dashboard cannot declare an empty list).
35
35
 
36
+ channel-agent.declaration (DEC-0150, FAC-SEM-162 to 165): extensions/channel-agent/0.1 under provider.extensions of the
37
+ manifest the descriptor names, or, with no manifest, under extensions of the well-known answer (CA-1). FAC-SEM-164's
38
+ obligations on a declaration still read FAIL, and so does a string shaped like a credential in it or in any copy beside
39
+ it; nothing declared, or a declaration read as not declared (a key elsewhere, another version, a form the schema or
40
+ FAC-SEM-163 refuses), is NOT_RUN.
41
+
36
42
  dashboard.opens-in-host (FAA-118, the operator rule of 2026-10-24): the service's checkout (--repo, else the one of
37
43
  the descriptor's source.repository that holds its commands, manifest or launchd job) opens the service's pages only
38
44
  through Fabric Dashboards. Tracked text files only, within a time budget; a browser opener aimed at its pages outside
@@ -85,6 +91,7 @@ from check_service_rules import well_known_actions_verdict, action_tools_verdict
85
91
  from check_service_rules import opens_in_host_verdict, service_checkout # noqa: E402 - FAA-118
86
92
  from check_service_rules import well_known_a2a_verdict, a2a_card_verdict # noqa: E402 - DEC-0122
87
93
  import fabric_a2a as fa2 # noqa: E402 - DEC-0122
94
+ import check_service_channel_agent as cac # noqa: E402 - DEC-0150, FAA-197
88
95
 
89
96
 
90
97
  class _PinnedHTTPS(http.client.HTTPSConnection):
@@ -248,6 +255,7 @@ class Probe:
248
255
  return
249
256
  try:
250
257
  self.wk = json.loads(body)
258
+ self.wk_bytes = len(body) # D4 of the 0.73.0 brief: a well-known answer shares a 2 MiB cap
251
259
  except ValueError:
252
260
  if self.remote:
253
261
  self.add_no_token(no_token, None)
@@ -638,6 +646,14 @@ class Probe:
638
646
  self.trace_rule(listing, sent)
639
647
  self.events_trace_rule(self.events)
640
648
 
649
+ def channel_agent_rule(self) -> None:
650
+ """DEC-0150 (FAA-197): the channel agent's declaration, read from the manifest the descriptor names, else from the
651
+ well-known answer (CA-1); one read as not declared is NOT_RUN with its evidence, never a FAIL (D3), except a string
652
+ shaped like a credential in it or in a copy the probe reads beside it (CA-5)."""
653
+ manifest, _, where = self.load_manifest()
654
+ self.add("channel-agent.declaration", *cac.declaration_verdict(
655
+ manifest, bool(self.d.get("fabricManifest")), where, self.wk, getattr(self, "wk_bytes", None)))
656
+
641
657
  def configuration_rule(self) -> None:
642
658
  """DEC-0046: a well-known `configuration` is {slots, resolved} as the schema types it; absent is NOT_RUN."""
643
659
  if not isinstance(self.wk, dict) or "configuration" not in self.wk:
@@ -893,6 +909,7 @@ class Probe:
893
909
  self.dashboard_page_rules()
894
910
  self.login_rules()
895
911
  self.interop_rules()
912
+ self.channel_agent_rule()
896
913
  verdict, evidence = board_responder_verdict(self.wk, self.board_kit)
897
914
  self.add("board.responder", verdict, evidence)
898
915
  self.lifecycle_rules()