@passioncode-ai/passioncode 0.2.17 → 0.2.18

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 (51) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/family.json +1 -1
  3. package/package.json +1 -1
  4. package/payload/.claude-plugin/marketplace.json +2 -2
  5. package/payload/manifest.json +8 -8
  6. package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  7. package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +13 -13
  8. package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +1 -1
  9. package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +4 -4
  10. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +41 -41
  11. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/demo.html +1 -1
  12. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +3 -3
  13. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
  14. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
  15. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
  16. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +12 -12
  17. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +4 -4
  18. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +1 -1
  19. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +4 -4
  20. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +13 -11
  21. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/estate-record.md +10 -5
  22. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/events-and-notifications.md +6 -6
  23. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +8 -6
  24. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +26 -26
  25. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +1 -1
  26. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +3 -2
  27. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/profiles.md +10 -10
  28. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +13 -13
  29. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +4 -4
  30. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/settings-backups.md +3 -3
  31. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +5 -5
  32. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/usage.md +5 -4
  33. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +20 -45
  34. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +1 -1
  35. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +1 -1
  36. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +2 -1
  37. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +1 -1
  38. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +28 -8
  39. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +1 -1
  40. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +1 -1
  41. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +1 -1
  42. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +34 -14
  43. package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +1 -1
  44. package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +33 -33
  45. package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +1 -1
  46. package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/resilience-and-autonomy.md +27 -27
  47. package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +31 -31
  48. package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +9 -9
  49. package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +8 -8
  50. package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +6 -6
  51. package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.18 - 2026-10-21
4
+
5
+ ### Changed
6
+
7
+ - **Fabric Agent Adapter is pinned at `v0.39.1`** (it was `v0.39.0`): fixes from a review of 0.39.0. The service
8
+ probe no longer crashes on a usage count that is not a number, the Python and Node kits read such counts as the
9
+ contract does, the documentation and the messages people read carry no em dash, and the dashboard kit is 1.1.1.
10
+
3
11
  ## 0.2.17 - 2026-10-20
4
12
 
5
13
  ### Changed
package/family.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "name": "fabric-agent-adapter",
9
9
  "displayName": "Fabric Agent Adapter",
10
10
  "repo": "passioncode-ai/fabric-agent-adapter",
11
- "ref": "v0.39.0",
11
+ "ref": "v0.39.1",
12
12
  "kind": "plugin",
13
13
  "path": "plugins/fabric-agent-adapter",
14
14
  "legacyPluginIds": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@passioncode-ai/passioncode",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "Set up PassionCode.ai on a computer with one command — the apps from their verified releases, their MCP servers for every coding agent and the PassionCode.ai skills — and check and repair it with the same command or `doctor`.",
5
5
  "bin": {
6
6
  "passioncode": "bin/passioncode.js"
@@ -11,7 +11,7 @@
11
11
  "name": "fabric-agent-adapter",
12
12
  "displayName": "Fabric Agent Adapter",
13
13
  "source": "./plugins/fabric-agent-adapter",
14
- "version": "0.39.0",
14
+ "version": "0.39.1",
15
15
  "description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
16
16
  "author": {
17
17
  "name": "PassionCode.ai",
@@ -35,7 +35,7 @@
35
35
  "name": "passioncode",
36
36
  "displayName": "PassionCode.ai",
37
37
  "source": "./plugins/passioncode",
38
- "version": "0.2.17",
38
+ "version": "0.2.18",
39
39
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
40
40
  "author": {
41
41
  "name": "PassionCode.ai",
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "family": "passioncode",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "release": true,
5
5
  "members": [
6
6
  {
7
7
  "name": "fabric-agent-adapter",
8
8
  "displayName": "Fabric Agent Adapter",
9
9
  "repo": "passioncode-ai/fabric-agent-adapter",
10
- "ref": "v0.39.0",
11
- "commit": "c963cae094507a77c36a7ffce7874c33c1e82ce6",
12
- "version": "0.39.0",
10
+ "ref": "v0.39.1",
11
+ "commit": "92037c3e0d27f4888806a1c4ae5b36167de50067",
12
+ "version": "0.39.1",
13
13
  "via": "clone of https://***@github.com/passioncode-ai/fabric-agent-adapter.git",
14
14
  "skills": [
15
15
  "adapting-projects-to-fabric",
@@ -23,7 +23,7 @@
23
23
  "legacyMarketplaces": [
24
24
  "fabric-agent-adapter"
25
25
  ],
26
- "contentHash": "sha256:cfbba2d29e3f8b9f4dcea236492c6e3840f458842fd9e2974334297ebbd4c5ad",
26
+ "contentHash": "sha256:4200dac01fb7296bd45ee2b52ff5a0fcec02e7e80bbb971c02f569feab84c1cb",
27
27
  "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.",
28
28
  "author": {
29
29
  "name": "PassionCode.ai",
@@ -62,9 +62,9 @@
62
62
  "name": "passioncode",
63
63
  "displayName": "PassionCode.ai",
64
64
  "repo": "passioncode-ai/passioncode",
65
- "ref": "v0.2.17",
65
+ "ref": "v0.2.18",
66
66
  "commit": null,
67
- "version": "0.2.17",
67
+ "version": "0.2.18",
68
68
  "via": "this repository",
69
69
  "skills": [
70
70
  "setting-up-passioncode",
@@ -72,7 +72,7 @@
72
72
  ],
73
73
  "legacyPluginIds": [],
74
74
  "legacyMarketplaces": [],
75
- "contentHash": "sha256:f81f2b67941736d09635868ceed06947c91fe6c2968b4bee3fe343e703508c13",
75
+ "contentHash": "sha256:6c506bf0504dbaa41ce2768e6205e8beba1bffff41c054e53b4eec230d7b5b3e",
76
76
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
77
77
  "author": {
78
78
  "name": "PassionCode.ai",
@@ -3,7 +3,7 @@
3
3
  "name": "fabric-agent-adapter",
4
4
  "displayName": "Fabric Agent Adapter",
5
5
  "description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; 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.39.1",
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.39.1"
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.
@@ -3,7 +3,7 @@ name: building-fabric-services
3
3
  description: >-
4
4
  Use when handing out or opening a Fabric service dashboard, building a local agent service on a
5
5
  macOS machine, making an ONLINE agent or dashboard (https origin, the remote placement) a
6
- Fabric service, or letting a service answer a Project's board requests — «сделай агенту дашборд»,
6
+ Fabric service, or letting a service answer a Project's board requests: «сделай агенту дашборд»,
7
7
  «локальный сервис агента», «подключи агента к Fabric Dashboards», «отвечать на запросы с доски проекта»,
8
8
  "make this agent a local service", "make an online dashboard a Fabric service", "add the
9
9
  well-known endpoint", «расходы агента на модели». Covers fabric-service/0.1:
@@ -18,7 +18,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
18
18
  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.
19
19
  metadata:
20
20
  author: PassionCode.ai
21
- version: "0.39.0"
21
+ version: "0.39.1"
22
22
  contract-version: "0.1.0"
23
23
  extension: "fabric-service/0.1"
24
24
  extension-commit: "c55f2d5a11c9a0197e958e87212fca7ae1154769"
@@ -29,7 +29,7 @@ metadata:
29
29
  A **service** is an agent that keeps running on the operator's computer: it holds
30
30
  state, answers other agents, and shows a dashboard. This skill makes one that is
31
31
  always alive, comes back after a restart, never runs twice, keeps its state through a
32
- reinstall, and appears in Fabric Dashboards by itself — the `fabric-service/0.1`
32
+ reinstall, and appears in Fabric Dashboards by itself: the `fabric-service/0.1`
33
33
  extension of the Fabric Agent Contract (DEC-0015).
34
34
 
35
35
  Every rule below exists because a real service on this estate broke it. Treat them as
@@ -41,15 +41,15 @@ re-deriving a rule.
41
41
  Use it to create a service, to bring an existing local server under the protocol, or
42
42
  to review one. Do not use it for:
43
43
 
44
- - a script, a cron job or a one-shot CLI — nothing stays running, so there is nothing
44
+ - a script, a cron job or a one-shot CLI: nothing stays running, so there is nothing
45
45
  to supervise; a launchd `StartInterval` job needs no descriptor;
46
46
  - a hosted product with no agent behind it. An online agent or dashboard that should appear in
47
- Fabric IS in scope: it is the remote placement — read [Online services](#online-services--the-remote-placement);
48
- - the provider manifest and admission bundle — that is `adapting-projects-to-fabric`
47
+ Fabric IS in scope: it is the remote placement; read [Online services](#online-services-the-remote-placement);
48
+ - the provider manifest and admission bundle: that is `adapting-projects-to-fabric`
49
49
  (a service that is also a provider does both);
50
50
  - the Fabric Dashboards app itself.
51
51
 
52
- ## Step 0 — is it a service?
52
+ ## Step 0: is it a service?
53
53
 
54
54
  It is a service when at least one is true: other agents call it while the operator is
55
55
  away; it runs jobs longer than one request; it owns a store other tools read; the
@@ -65,7 +65,7 @@ Answer before writing code, and record the answers in the project README:
65
65
  | What it stores | the store, where it lives (Step 2, rule 5), and what survives uninstall |
66
66
  | What it tells the operator | the events worth a notification (Step 5) |
67
67
 
68
- ## Step 1 — choose the surfaces
68
+ ## Step 1: choose the surfaces
69
69
 
70
70
  | Caller | Surface | Why |
71
71
  |---|---|---|
@@ -103,14 +103,14 @@ responder in its own process: [`scripts/fabric_hub.py`](scripts/fabric_hub.py) f
103
103
  every step and stops on `fenced`, `lease_expired` or `authority_changed` (Node: `fabric-hub.mjs`, `fabric-board.mjs`).
104
104
  The request body is data behind the service's own input gate. Read [the board reference](references/board.md).
105
105
 
106
- ## Step 2 — the non-negotiables
106
+ ## Step 2: the non-negotiables
107
107
 
108
108
  1. **Loopback only.** Bind `127.0.0.1`. Refuse any `Host` other than
109
109
  `127.0.0.1:<port>`, `localhost:<port>`, `[::1]:<port>`; refuse a foreign `Origin` and
110
- `Sec-Fetch-Site: cross-site` — on every path, the well-known one included.
110
+ `Sec-Fetch-Site: cross-site`, on every path, the well-known one included.
111
111
  *(A throwaway `python -m http.server` bound to every interface served a source tree to the local network.)*
112
112
  2. **One copy, locked before any side effect.** Take the exclusive lock on
113
- `<data>/service.lock` first — before resuming jobs, starting a scheduler, migrating
113
+ `<data>/service.lock` first, before resuming jobs, starting a scheduler, migrating
114
114
  a store or even creating a token. Held → print one sentence naming the holder's pid
115
115
  and exit **75**. Binding the port is not a lock. Under launchd the kit backs off
116
116
  in-process first (up to 300 s), so a duplicate is a few starts an hour, not a
@@ -127,11 +127,11 @@ The request body is data behind the service's own input gate. Read [the board re
127
127
  5. **State outside code.** Data and config in `~/Library/Application Support/<id>/`,
128
128
  logs in `~/Library/Logs/<id>/`, cache in `~/Library/Caches/<id>/`; the service's own
129
129
  access token in a 0600 file it generates (principle 6). **Every provider credential the
130
- service uses comes from Project Observatory, by name** — the plist starts the service
130
+ service uses comes from Project Observatory, by name**: the plist starts the service
131
131
  with `use_secret.py serve --consumer <label> <project> <NAME>[,<NAME>] -- <command>`, which
132
132
  reads the vault only and records the consumer so a rotation names it; never a copy of a
133
133
  key in a `.env`, a config file or the plist. Never inside the service's own code checkout or a release directory; a
134
- repository that versions the data itself is a store and is fine — declare
134
+ repository that versions the data itself is a store and is fine; declare
135
135
  `source.repository` so the probe can tell them apart. *(Deleting a checkout left a
136
136
  plist launchd retried every 10 s, and the data went with it.)*
137
137
  6. **Tokens stay in files and headers.** Mode 0600, owner-checked, never a symlink;
@@ -139,16 +139,16 @@ The request body is data behind the service's own input gate. Read [the board re
139
139
  one-time login code, never the token.
140
140
  7. **`degraded` is always present.** An empty list asserts full health; `ready` with a
141
141
  non-empty list is a lie the kit corrects to `degraded`.
142
- 8. **Atomic writes.** Temporary file, fsync, rename — for the store's side files, the
142
+ 8. **Atomic writes.** Temporary file, fsync, rename, for the store's side files, the
143
143
  descriptor and the token.
144
144
 
145
- ## Step 3 — build it with the kit
145
+ ## Step 3: build it with the kit
146
146
 
147
147
  Copy the kit into the service (each is one self-contained file): Python
148
148
  [`scripts/fabric_service.py`](scripts/fabric_service.py), Node
149
149
  [`scripts/fabric-service.mjs`](scripts/fabric-service.mjs). Both share file formats, and
150
150
  their locks exclude each other. The complete worked example is
151
- [`scripts/sample_service.py`](scripts/sample_service.py) — read it before writing a
151
+ [`scripts/sample_service.py`](scripts/sample_service.py); read it before writing a
152
152
  handler.
153
153
 
154
154
  Startup order is the part that goes wrong; keep it exactly:
@@ -157,7 +157,7 @@ Startup order is the part that goes wrong; keep it exactly:
157
157
  import fabric_service as fs
158
158
 
159
159
  dirs = fs.service_dirs("example-agent")
160
- lock = fs.hold_single_instance(dirs["data"]) # 1. lock — exits 75 if held (backs off first under launchd)
160
+ lock = fs.hold_single_instance(dirs["data"]) # 1. lock: exits 75 if held (backs off first under launchd)
161
161
  token = fs.ensure_token(dirs["data"] / "service.token") # 2. only now touch state
162
162
  log = fs.JsonlEventLog(dirs["data"] / "events.jsonl") # (or a view over your own log)
163
163
  codes = fs.LoginCodes(dirs["data"] / "auth")
@@ -172,12 +172,12 @@ On every request call `check_request(port, host, origin, sec_fetch_site)` and an
172
172
 
173
173
  | Route | Auth | Kit |
174
174
  |---|---|---|
175
- | `GET /.well-known/fabric-service` | none, guard still applies | `build_well_known(...)` — from memory, under 100 ms |
175
+ | `GET /.well-known/fabric-service` | none, guard still applies | `build_well_known(...)`, from memory, under 100 ms |
176
176
  | `GET /fabric/v1/events?after=&limit=` | service token | `events_page(fetch, after, parse_limit(limit))` |
177
177
  | `POST /fabric/v1/login-code` | service token | `LoginCodes.issue()` |
178
178
  | `GET /fabric/v1/login?code=` | the code | `LoginCodes.redeem(code)` → `Set-Cookie: session_cookie_header(...)`, 302 to the dashboard |
179
179
 
180
- `SIGTERM` drains in-flight work, then exits — 10 s at most, inside `ExitTimeOut`
180
+ `SIGTERM` drains in-flight work, then exits: 10 s at most, inside `ExitTimeOut`
181
181
  (`fs.Drain` / `new Drain()`: `with drain.work():` refuses new work once a stop began);
182
182
  interrupted work resumes on the next start. Log through `RotatingLog` (5 × 5 MB, 0600)
183
183
  and call `cap_stdout_log` once at start.
@@ -187,18 +187,18 @@ in Python; jobs live in `fabric_interop.JobStore(dirs["data"] / "jobs")`, create
187
187
  the lock like every other piece of state. Add `"mcp": {"path": "/mcp", "transport":
188
188
  "streamable-http", "capabilities": [...]}` to the well-known surfaces, and point the
189
189
  descriptor's `fabricManifest` at a manifest whose service key names this
190
- `<id>.<instance>` — `sample_service.py register` shows both.
190
+ `<id>.<instance>`; `sample_service.py register` shows both.
191
191
 
192
- ## Step 4 — install it
192
+ ## Step 4: install it
193
193
 
194
194
  The installer, not the service, owns the plist and the descriptor. Sequence:
195
195
 
196
- 1. `write_descriptor(descriptor)` — refuses a port or `id.instance` another descriptor
197
- claims. A preview or branch copy is a second **instance**, never a second id — and it is
196
+ 1. `write_descriptor(descriptor)`: refuses a port or `id.instance` another descriptor
197
+ claims. A preview or branch copy is a second **instance**, never a second id, and it is
198
198
  one more service the operator sees, probes and gets notified by. Verify a release with its
199
199
  own doctor or self-check before it replaces `default`; a temporary instance is uninstalled
200
200
  (`launchd_uninstall`, `remove_descriptor`) as soon as its check is done, not left running.
201
- 2. `launchd_plist(...)` then `launchd_install(...)` — writes and lints the plist,
201
+ 2. `launchd_plist(...)` then `launchd_install(...)`: writes and lints the plist,
202
202
  `bootout` and waits for the unload, `bootstrap` with retries on the transient I/O
203
203
  error, then polls the well-known document until it answers with **this** identity.
204
204
  A label the operator disabled stays disabled: only a first install enables.
@@ -217,7 +217,7 @@ rewrites the plist and restarts. Read [the lifecycle reference](references/lifec
217
217
  for the plist fields, the release layout, log rotation, behaving under a host lifecycle broker
218
218
  and the Linux and Windows supervisors.
219
219
 
220
- ## Step 5 — the dashboard and the events
220
+ ## Step 5: the dashboard and the events
221
221
 
222
222
  The dashboard is a same-origin page: no inline script, strict CSP, polling that pauses
223
223
  while the operator types or a dialog is open, one panel's failure never blanks the
@@ -235,10 +235,10 @@ and declare it with `extensions=fs.dashboard_extension()`. Read
235
235
  declaration and how to upgrade a dashboard built before the kit: an upgrade you may make yourself,
236
236
  which the plugin's session-start notice offers in a repository that owns the service.
237
237
 
238
- The events feed is a **view over the log you already keep** — a jobs table, a JSONL
239
- journal — not a second store. Each event is one sentence a person reads; set
238
+ The events feed is a **view over the log you already keep** (a jobs table, a JSONL
239
+ journal), not a second store. Each event is one sentence a person reads; set
240
240
  `notify: true` only when the operator must decide, or something failed or degrades their
241
- work — once per episode, with a `subject` and a `link` to the page that resolves it. A
241
+ work, once per episode, with a `subject` and a `link` to the page that resolves it. A
242
242
  question's kind says so (`*.awaiting_*`, `*.approval_*`, `human_step.opened`). The service
243
243
  raises no banners of its own: the host is the one channel. Read
244
244
  [the events reference](references/events-and-notifications.md) for mapping an existing
@@ -253,9 +253,9 @@ A service whose store holds what the operator decided keeps **settings backups**
253
253
  directory, restores only on a fresh database and never overwrites. Read
254
254
  [the settings backups reference](references/settings-backups.md).
255
255
 
256
- ## Step 6 — verify
256
+ ## Step 6: verify
257
257
 
258
- Run the probe against the live service — it reads the descriptor, then checks every
258
+ Run the probe against the live service: it reads the descriptor, then checks every
259
259
  rule it can reach and says which it could not:
260
260
 
261
261
  ```bash
@@ -268,7 +268,7 @@ events auth and shape, single-use login, state outside code, instance lock, plis
268
268
  launchd pid equals answering pid, `dashboard.declared` (ED-9), and the `interop.*` rules:
269
269
  manifest link, capability list, tools equal to the manifest, job tools, unknown job, trace
270
270
  propagation, event trace pairs, and `board.responder` for a service that declares the project board) and exits 1 on
271
- any `FAIL`. A `NOT_RUN` is not a pass —
271
+ any `FAIL`. A `NOT_RUN` is not a pass;
272
272
  name it in the report. A service with a dashboard also runs the layout probe,
273
273
  `node <skill-dir>/scripts/check_dashboard_layout.mjs --service <id>` (WebKit at 360, 480, 768
274
274
  and 1280 px; needs Playwright, else `NOT_RUN`).
@@ -277,7 +277,7 @@ Then prove the lock: start a second copy by hand against the same data directory
277
277
  must exit 75 while the first keeps serving. Prove recovery: `kill -9` the launchd pid;
278
278
  the well-known document must answer again with a new pid within about 15 seconds.
279
279
 
280
- ## Packing and signing it — `fabric-package/1`
280
+ ## Packing and signing it: `fabric-package/1`
281
281
 
282
282
  To hand an agent to another machine or an organization, pack it as one folder (contract DEC-0050, DEC-0051). Write the
283
283
  author's `fabric.package.json` (the descriptive fields; for an agent `resultSignal` and `evals` with the receipt of the
@@ -313,11 +313,11 @@ first commit:
313
313
  org-index `scripts/check_format.py` reports 0 findings for it before it is called done. **An agent
314
314
  someone builds for themselves is not a PassionCode.ai repository:** its licence is its owner's
315
315
  choice, nothing about it is published or listed by the organization, and none of these files is
316
- required of it — though the verified MCP quick start is still how anyone learns to drive it.
316
+ required of it, though the verified MCP quick start is still how anyone learns to drive it.
317
317
 
318
- ## Online services — the remote placement
318
+ ## Online services: the remote placement
319
319
 
320
- An agent or a dashboard that runs online — on a platform, a server, a hosted app — becomes a
320
+ An agent or a dashboard that runs online (on a platform, a server, a hosted app) becomes a
321
321
  Fabric service with the same four routes and one descriptor on the operator's computer
322
322
  (`placement: "remote"`, DEC-0019). Nothing about launchd, the lock or loopback applies; three
323
323
  things change and the kits implement each:
@@ -328,7 +328,7 @@ things change and the kits implement each:
328
328
  | Well-known | only for the token; otherwise `401` with an **empty** body | `wellKnownAllowed('remote', …)` / `well_known_allowed` |
329
329
  | Session | `__Host-fabric_session`, `Secure`; codes in memory, the key from a platform secret so sessions survive a deploy | `remoteSessionCookieHeader`, `new LoginCodes(null, 120, { store: new MemoryCodeStore(), key })` |
330
330
 
331
- 1. **Serve the four routes** in the app that already exists — not beside it. The complete worked
331
+ 1. **Serve the four routes** in the app that already exists, not beside it. The complete worked
332
332
  example is [`scripts/sample-remote-service.mjs`](scripts/sample-remote-service.mjs): it runs
333
333
  with its own TLS or behind a platform router.
334
334
  2. **Secrets live on the platform:** the service token and the session key (32 bytes) are
@@ -336,7 +336,7 @@ things change and the kits implement each:
336
336
  remote service needs is issued and kept in Project Observatory, pushed to the platform, and
337
337
  the movement recorded with `vault.py moved --at <provider>`, so the platform's copy is
338
338
  known rather than invisible.
339
- 3. **Register it on the operator's computer** — the installer side, run there:
339
+ 3. **Register it on the operator's computer**, the installer side, run there:
340
340
  `registerRemote({ id, name, origin, token })` / `register_remote(...)` writes the token file
341
341
  (0600) and the descriptor; pass the token from a file or stdin, never in argv. Public names
342
342
  only in public artifacts: a private service is registered by a local descriptor and nowhere
@@ -350,7 +350,7 @@ behaviour a host shows, rotation, a multi-process platform, and what a host will
350
350
 
351
351
  ## Migrating an existing service
352
352
 
353
- Read [the migration reference](references/migrating-a-service.md) — the order of
353
+ Read [the migration reference](references/migrating-a-service.md): the order of
354
354
  changes that keeps the service answering throughout, and what each existing service on
355
355
  this estate needs.
356
356
 
@@ -367,14 +367,14 @@ this estate needs.
367
367
  against [the protocol reference](references/protocol.md); the probe is the judge.
368
368
  - **No contract checkout:** the protocol reference is pinned to the extension commit
369
369
  in this skill's metadata; do not reconstruct fields from memory.
370
- - **Fabric Dashboards not installed:** nothing changes — the service is complete
370
+ - **Fabric Dashboards not installed:** nothing changes; the service is complete
371
371
  without a host; the descriptor waits for one.
372
372
 
373
373
  ## Gotchas
374
374
 
375
375
  - `lsof` shows `*:<port>` or `0.0.0.0` → the bind is wrong even if the Host check works.
376
376
  - A health probe that only checks HTTP 200 accepts any program on the port. Compare
377
- `service.id` and `service.instance` — two services here once defaulted to ports
377
+ `service.id` and `service.instance`: two services here once defaulted to ports
378
378
  another service already held.
379
379
  - `launchctl bootstrap` right after `bootout` fails with I/O error 5 until the unload
380
380
  finishes; wait, then retry.
@@ -397,7 +397,7 @@ the probe table verbatim with every `NOT_RUN` explained; the lock and kill-9 res
397
397
  with pids; and the one next command. Never call a service conformant while the probe
398
398
  reports a `FAIL`.
399
399
 
400
- ## Dashboard handoff — also for consumers
400
+ ## Dashboard handoff: also for consumers
401
401
 
402
402
  When handing a registered service dashboard to a person, or writing the generated
403
403
  agent's completion/notification instructions, read and apply
@@ -65,7 +65,7 @@
65
65
  <tbody>
66
66
  <tr><td class="fd-mono">job-7f3a91</td><td>example.summarize</td><td><span class="fd-chip fd-s-info"><span class="fd-dot"></span>Running</span></td><td><time>2026-10-11 17:02</time></td><td class="fd-num">12 480</td><td class="fd-num">$0.031</td><td class="fd-mono">4bf92f3577b34da6a3ce929d0e0e4736</td></tr>
67
67
  <tr><td class="fd-mono">job-7f3a90</td><td>example.translate</td><td><span class="fd-chip fd-s-ok"><span class="fd-dot"></span>Done</span></td><td><time>2026-10-11 16:40</time></td><td class="fd-num">8 002</td><td class="fd-num">$0.019</td><td class="fd-mono">00f067aa0ba902b74bf92f3577b34da6</td></tr>
68
- <tr><td class="fd-mono">job-7f3a8f</td><td>example.review</td><td><span class="fd-chip fd-s-warn"><span class="fd-dot"></span>Needs you</span></td><td><time>2026-10-11 15:12</time></td><td class="fd-num">2 210</td><td class="fd-num">—</td><td class="fd-mono">a3ce929d0e0e47364bf92f3577b34da6</td></tr>
68
+ <tr><td class="fd-mono">job-7f3a8f</td><td>example.review</td><td><span class="fd-chip fd-s-warn"><span class="fd-dot"></span>Needs you</span></td><td><time>2026-10-11 15:12</time></td><td class="fd-num">2 210</td><td class="fd-num">none</td><td class="fd-mono">a3ce929d0e0e47364bf92f3577b34da6</td></tr>
69
69
  </tbody>
70
70
  </table>
71
71
  </div>
@@ -1,4 +1,4 @@
1
- /* fabric-dashboard-kit@1.1.0 · Fabric's button (Fabric Agent Contract DEC-0040, FB-1…FB-8, FL-1…FL-6)
1
+ /* fabric-dashboard-kit@1.1.1 · Fabric's button (Fabric Agent Contract DEC-0040, FB-1…FB-8, FL-1…FL-6)
2
2
  Load it same-origin, after fabric-dashboard.css, with the service it opens Fabric on:
3
3
  <script src="fabric-button.js" defer data-service="example-agent.default" data-service-name="Example Agent"
4
4
  data-project="project-a" data-project-name="Project A"></script>
@@ -10,7 +10,7 @@
10
10
  (function (root) {
11
11
  'use strict';
12
12
 
13
- var VERSION = '1.1.0';
13
+ var VERSION = '1.1.1';
14
14
  var COOKIE = 'fabric_button';
15
15
  var GET_FABRIC = 'https://passioncode.ai/fabric';
16
16
  var ABSENT_AFTER_MS = 1500;
@@ -212,7 +212,7 @@
212
212
  return a;
213
213
  });
214
214
  var note = el(doc, 'p', { 'class': 'fd-fabric-button-note', role: 'note' });
215
- note.appendChild(doc.createTextNode('Fabric is not installed — get it at '));
215
+ note.appendChild(doc.createTextNode('Fabric is not installed. Get it at '));
216
216
  note.appendChild(el(doc, 'a', { href: GET_FABRIC, target: '_blank', rel: 'noopener', 'class': 'fd-fabric-button-get' }, 'passioncode.ai/fabric'));
217
217
  note.hidden = !absent;
218
218
  menu.appendChild(note);
@@ -1,4 +1,4 @@
1
- /* fabric-dashboard-kit@1.1.0 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
1
+ /* fabric-dashboard-kit@1.1.1 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
2
2
  A Fabric service dashboard shown inside a host pane: usable from 360 CSS px up, navigation always
3
3
  reachable, wide content in its own scroll box, one vertical scroller, appearance from the host.
4
4
  Copy this file next to fabric-dashboard.js; do not edit it in place. Put the page's own rules in
@@ -1,4 +1,4 @@
1
- /* fabric-dashboard-kit@1.1.0 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
1
+ /* fabric-dashboard-kit@1.1.1 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
2
2
  Load it same-origin with <script src="fabric-dashboard.js" defer></script>: no inline script, no
3
3
  eval, nothing from a CDN. It applies the host's appearance (ED-6, ED-8), folds navigation that
4
4
  does not fit into a More menu (ED-3), makes wide boxes keyboard-reachable (ED-4) and keeps
@@ -8,7 +8,7 @@
8
8
  'use strict';
9
9
 
10
10
  var KIT = 'fabric-dashboard-kit';
11
- var VERSION = '1.1.0';
11
+ var VERSION = '1.1.1';
12
12
  /* fabric-dashboard-kit:theme-ids:begin */
13
13
  var THEMES = ['graphite', 'fabric', 'paper', 'forest', 'ocean', 'ember', 'contrast'];
14
14
  /* fabric-dashboard-kit:theme-ids:end */
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabric-dashboard-kit",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "profile": "fabric-dashboard/0.1",
5
5
  "decision": "DEC-0036",
6
6
  "declarationKey": "https://fabric.passioncode.ai/agent-contract/extensions/dashboard/0.1",
@@ -15,9 +15,9 @@
15
15
  "contrast"
16
16
  ],
17
17
  "files": {
18
- "fabric-dashboard.css": "498571903fac6dfd2d6645283da2f703fa945f410f2fafa269a8c9c322735c3b",
19
- "fabric-dashboard.js": "100f55d940d4ed60aa8511cee4c65219c93114eb7d7a66639b0e4e4d7aa05f22",
20
- "fabric-button.js": "4f1e100936ae65af5539594681e66092ae1834a4952da547a67d0558c9fadbbe",
18
+ "fabric-dashboard.css": "a8847c8e2f386572318842ec1d1613fcb29e4aec060e033c060d8dba6b7c6f02",
19
+ "fabric-dashboard.js": "d0fc41144a6bd413383bd53bbfa6e01a29547c7ec9c01a3927d69fb36cd71a7d",
20
+ "fabric-button.js": "f5599fabfeadfb5c69d30f7ea500846521a166470078a736291c7753014bc25c",
21
21
  "themes.json": "511839f1a1a83eb37fadfd132791474497d5c28c5091700b9aa31ad076e359b5"
22
22
  },
23
23
  "history": {
@@ -29,6 +29,11 @@
29
29
  "fabric-dashboard.css": "498571903fac6dfd2d6645283da2f703fa945f410f2fafa269a8c9c322735c3b",
30
30
  "fabric-dashboard.js": "100f55d940d4ed60aa8511cee4c65219c93114eb7d7a66639b0e4e4d7aa05f22",
31
31
  "fabric-button.js": "4f1e100936ae65af5539594681e66092ae1834a4952da547a67d0558c9fadbbe"
32
+ },
33
+ "1.1.1": {
34
+ "fabric-dashboard.css": "a8847c8e2f386572318842ec1d1613fcb29e4aec060e033c060d8dba6b7c6f02",
35
+ "fabric-dashboard.js": "d0fc41144a6bd413383bd53bbfa6e01a29547c7ec9c01a3927d69fb36cd71a7d",
36
+ "fabric-button.js": "f5599fabfeadfb5c69d30f7ea500846521a166470078a736291c7753014bc25c"
32
37
  }
33
38
  }
34
39
  }