@passioncode-ai/passioncode 0.2.16 → 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.
- package/CHANGELOG.md +17 -0
- package/family.json +1 -1
- package/package.json +1 -1
- package/payload/.claude-plugin/marketplace.json +2 -2
- package/payload/manifest.json +8 -8
- package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +15 -15
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +4 -4
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +44 -43
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/demo.html +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +3 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +12 -12
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +4 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +4 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +19 -9
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/estate-record.md +19 -9
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/events-and-notifications.md +6 -6
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +8 -6
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +26 -26
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +10 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/profiles.md +10 -10
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +14 -14
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +4 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/settings-backups.md +3 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +5 -5
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/usage.md +8 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +20 -43
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +9 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +33 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +40 -13
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +15 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +32 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +52 -18
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +35 -35
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/resilience-and-autonomy.md +27 -27
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/where-agents-run.md +2 -1
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +31 -31
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +9 -9
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +8 -8
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +6 -6
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
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
|
+
|
|
11
|
+
## 0.2.17 - 2026-10-20
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Fabric Agent Adapter is pinned at `v0.39.0`** (it was `v0.38.0`): the kits follow contract `c55f2d5`. A partner's
|
|
16
|
+
publisher key is trusted only in the organization contexts its scope names (FAC-SEM-122), a partner may sit innermost
|
|
17
|
+
in a delegation chain (DEC-0090), and a usage report counts calls with unknown tokens in `unmeasuredCalls`
|
|
18
|
+
(DEC-0091).
|
|
19
|
+
|
|
3
20
|
## 0.2.16 - 2026-10-20
|
|
4
21
|
|
|
5
22
|
### Changed
|
package/family.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/passioncode",
|
|
3
|
-
"version": "0.2.
|
|
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.
|
|
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.
|
|
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",
|
package/payload/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"family": "passioncode",
|
|
3
|
-
"version": "0.2.
|
|
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.
|
|
11
|
-
"commit": "
|
|
12
|
-
"version": "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:
|
|
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.
|
|
65
|
+
"ref": "v0.2.18",
|
|
66
66
|
"commit": null,
|
|
67
|
-
"version": "0.2.
|
|
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:
|
|
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.
|
|
6
|
+
"version": "0.39.1",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -1,13 +1,13 @@
|
|
|
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
|
|
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.
|
|
8
|
+
version: "0.39.1"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "c55f2d5a11c9a0197e958e87212fca7ae1154769"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Adapting projects to Fabric
|
|
@@ -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)
|
|
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
|
|
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,
|
|
@@ -70,7 +70,7 @@ Use exactly:
|
|
|
70
70
|
|
|
71
71
|
- contract version `0.1.0`;
|
|
72
72
|
- repository `https://github.com/passioncode-ai/fabric-agent-contract`;
|
|
73
|
-
- commit `
|
|
73
|
+
- commit `c55f2d5a11c9a0197e958e87212fca7ae1154769`.
|
|
74
74
|
|
|
75
75
|
This is the default for new bundles. When checking an issued legacy bundle, preserve its
|
|
76
76
|
explicit supported lock and use that exact clean checkout. Never silently upgrade or
|
|
@@ -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
|
|
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
|
|
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
|
|
178
|
-
plugin; serve it over HTTP from one resident process or register it at project scope
|
|
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
|
|
218
|
-
bare `/command` in a group is not addressed
|
|
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
|
|
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
|
|
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
|
|
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
|
|
@@ -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
|
|
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`
|
|
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
|
|
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
|
|
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.
|
|
@@ -21,10 +21,10 @@ import fabric_secrets as _secrets # noqa: E402 - the contract's credential dete
|
|
|
21
21
|
|
|
22
22
|
CONTRACT_VERSION = "0.1.0"
|
|
23
23
|
CONTRACT_REPOSITORY = "https://github.com/passioncode-ai/fabric-agent-contract"
|
|
24
|
-
CONTRACT_COMMIT = "
|
|
24
|
+
CONTRACT_COMMIT = "c55f2d5a11c9a0197e958e87212fca7ae1154769"
|
|
25
25
|
# #region supported-contract-revisions — docs: README.md#contract-pin
|
|
26
26
|
# Only this declaration may name a legacy revision in live files.
|
|
27
|
-
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "d8146cfb0a1c74fc6432284c4356bb0c864b37b5", "82e163665e156a08aa3b92e4711015582c06162c", "1636fa97262f4a26e2086572d540c2ee701e0010", "f00a7685e3861c27f7899c033fb850a145a1708f", "a046f57cf46ea9e3da57ff8ce6a3ed4d26d8774b", "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0", "b291bf09e0a9f9fd3c16cf540832cd021203b7d1", "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
27
|
+
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "07042181bfae2a481aa0da1a5651f24c76669c48", "d8146cfb0a1c74fc6432284c4356bb0c864b37b5", "82e163665e156a08aa3b92e4711015582c06162c", "1636fa97262f4a26e2086572d540c2ee701e0010", "f00a7685e3861c27f7899c033fb850a145a1708f", "a046f57cf46ea9e3da57ff8ce6a3ed4d26d8774b", "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0", "b291bf09e0a9f9fd3c16cf540832cd021203b7d1", "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
28
28
|
# #endregion supported-contract-revisions
|
|
29
29
|
INTEROP_KEY = "https://fabric.passioncode.ai/agent-contract/extensions/interop/0.1"
|
|
30
30
|
MCP_REVISION = "2026-07-28"
|
|
@@ -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,10 +18,10 @@ 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.
|
|
21
|
+
version: "0.39.1"
|
|
22
22
|
contract-version: "0.1.0"
|
|
23
23
|
extension: "fabric-service/0.1"
|
|
24
|
-
extension-commit: "
|
|
24
|
+
extension-commit: "c55f2d5a11c9a0197e958e87212fca7ae1154769"
|
|
25
25
|
---
|
|
26
26
|
|
|
27
27
|
# Building Fabric services
|
|
@@ -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
|
|
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
|
|
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
|
|
48
|
-
- the provider manifest and admission bundle
|
|
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
|
|
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
|
|
68
|
+
## Step 1: choose the surfaces
|
|
69
69
|
|
|
70
70
|
| Caller | Surface | Why |
|
|
71
71
|
|---|---|---|
|
|
@@ -84,7 +84,8 @@ effect nobody saw, have their own codes and a key per caller (DEC-0087). Read
|
|
|
84
84
|
[the interop reference](references/interop.md) before writing an MCP tool; the helpers
|
|
85
85
|
are in [`scripts/fabric_interop.py`](scripts/fabric_interop.py) and
|
|
86
86
|
[`scripts/fabric-interop.mjs`](scripts/fabric-interop.mjs). When the callers are agents of the estate, the
|
|
87
|
-
service checks each call's delegation token (DEC-0039
|
|
87
|
+
service checks each call's delegation token (DEC-0039; a partner's agent carries the partner innermost, DEC-0090):
|
|
88
|
+
read [the delegation reference](references/delegation.md);
|
|
88
89
|
the verifier is [`scripts/fabric_delegation.py`](scripts/fabric_delegation.py) /
|
|
89
90
|
[`scripts/fabric-delegation.mjs`](scripts/fabric-delegation.mjs). A service on the operator's machines that
|
|
90
91
|
applies the estate record (DEC-0055) verifies each revision first and trusts only the keys it certifies, and runs an
|
|
@@ -102,14 +103,14 @@ responder in its own process: [`scripts/fabric_hub.py`](scripts/fabric_hub.py) f
|
|
|
102
103
|
every step and stops on `fenced`, `lease_expired` or `authority_changed` (Node: `fabric-hub.mjs`, `fabric-board.mjs`).
|
|
103
104
|
The request body is data behind the service's own input gate. Read [the board reference](references/board.md).
|
|
104
105
|
|
|
105
|
-
## Step 2
|
|
106
|
+
## Step 2: the non-negotiables
|
|
106
107
|
|
|
107
108
|
1. **Loopback only.** Bind `127.0.0.1`. Refuse any `Host` other than
|
|
108
109
|
`127.0.0.1:<port>`, `localhost:<port>`, `[::1]:<port>`; refuse a foreign `Origin` and
|
|
109
|
-
`Sec-Fetch-Site: cross-site
|
|
110
|
+
`Sec-Fetch-Site: cross-site`, on every path, the well-known one included.
|
|
110
111
|
*(A throwaway `python -m http.server` bound to every interface served a source tree to the local network.)*
|
|
111
112
|
2. **One copy, locked before any side effect.** Take the exclusive lock on
|
|
112
|
-
`<data>/service.lock` first
|
|
113
|
+
`<data>/service.lock` first, before resuming jobs, starting a scheduler, migrating
|
|
113
114
|
a store or even creating a token. Held → print one sentence naming the holder's pid
|
|
114
115
|
and exit **75**. Binding the port is not a lock. Under launchd the kit backs off
|
|
115
116
|
in-process first (up to 300 s), so a duplicate is a few starts an hour, not a
|
|
@@ -126,11 +127,11 @@ The request body is data behind the service's own input gate. Read [the board re
|
|
|
126
127
|
5. **State outside code.** Data and config in `~/Library/Application Support/<id>/`,
|
|
127
128
|
logs in `~/Library/Logs/<id>/`, cache in `~/Library/Caches/<id>/`; the service's own
|
|
128
129
|
access token in a 0600 file it generates (principle 6). **Every provider credential the
|
|
129
|
-
service uses comes from Project Observatory, by name
|
|
130
|
+
service uses comes from Project Observatory, by name**: the plist starts the service
|
|
130
131
|
with `use_secret.py serve --consumer <label> <project> <NAME>[,<NAME>] -- <command>`, which
|
|
131
132
|
reads the vault only and records the consumer so a rotation names it; never a copy of a
|
|
132
133
|
key in a `.env`, a config file or the plist. Never inside the service's own code checkout or a release directory; a
|
|
133
|
-
repository that versions the data itself is a store and is fine
|
|
134
|
+
repository that versions the data itself is a store and is fine; declare
|
|
134
135
|
`source.repository` so the probe can tell them apart. *(Deleting a checkout left a
|
|
135
136
|
plist launchd retried every 10 s, and the data went with it.)*
|
|
136
137
|
6. **Tokens stay in files and headers.** Mode 0600, owner-checked, never a symlink;
|
|
@@ -138,16 +139,16 @@ The request body is data behind the service's own input gate. Read [the board re
|
|
|
138
139
|
one-time login code, never the token.
|
|
139
140
|
7. **`degraded` is always present.** An empty list asserts full health; `ready` with a
|
|
140
141
|
non-empty list is a lie the kit corrects to `degraded`.
|
|
141
|
-
8. **Atomic writes.** Temporary file, fsync, rename
|
|
142
|
+
8. **Atomic writes.** Temporary file, fsync, rename, for the store's side files, the
|
|
142
143
|
descriptor and the token.
|
|
143
144
|
|
|
144
|
-
## Step 3
|
|
145
|
+
## Step 3: build it with the kit
|
|
145
146
|
|
|
146
147
|
Copy the kit into the service (each is one self-contained file): Python
|
|
147
148
|
[`scripts/fabric_service.py`](scripts/fabric_service.py), Node
|
|
148
149
|
[`scripts/fabric-service.mjs`](scripts/fabric-service.mjs). Both share file formats, and
|
|
149
150
|
their locks exclude each other. The complete worked example is
|
|
150
|
-
[`scripts/sample_service.py`](scripts/sample_service.py)
|
|
151
|
+
[`scripts/sample_service.py`](scripts/sample_service.py); read it before writing a
|
|
151
152
|
handler.
|
|
152
153
|
|
|
153
154
|
Startup order is the part that goes wrong; keep it exactly:
|
|
@@ -156,7 +157,7 @@ Startup order is the part that goes wrong; keep it exactly:
|
|
|
156
157
|
import fabric_service as fs
|
|
157
158
|
|
|
158
159
|
dirs = fs.service_dirs("example-agent")
|
|
159
|
-
lock = fs.hold_single_instance(dirs["data"]) # 1. lock
|
|
160
|
+
lock = fs.hold_single_instance(dirs["data"]) # 1. lock: exits 75 if held (backs off first under launchd)
|
|
160
161
|
token = fs.ensure_token(dirs["data"] / "service.token") # 2. only now touch state
|
|
161
162
|
log = fs.JsonlEventLog(dirs["data"] / "events.jsonl") # (or a view over your own log)
|
|
162
163
|
codes = fs.LoginCodes(dirs["data"] / "auth")
|
|
@@ -171,12 +172,12 @@ On every request call `check_request(port, host, origin, sec_fetch_site)` and an
|
|
|
171
172
|
|
|
172
173
|
| Route | Auth | Kit |
|
|
173
174
|
|---|---|---|
|
|
174
|
-
| `GET /.well-known/fabric-service` | none, guard still applies | `build_well_known(...)
|
|
175
|
+
| `GET /.well-known/fabric-service` | none, guard still applies | `build_well_known(...)`, from memory, under 100 ms |
|
|
175
176
|
| `GET /fabric/v1/events?after=&limit=` | service token | `events_page(fetch, after, parse_limit(limit))` |
|
|
176
177
|
| `POST /fabric/v1/login-code` | service token | `LoginCodes.issue()` |
|
|
177
178
|
| `GET /fabric/v1/login?code=` | the code | `LoginCodes.redeem(code)` → `Set-Cookie: session_cookie_header(...)`, 302 to the dashboard |
|
|
178
179
|
|
|
179
|
-
`SIGTERM` drains in-flight work, then exits
|
|
180
|
+
`SIGTERM` drains in-flight work, then exits: 10 s at most, inside `ExitTimeOut`
|
|
180
181
|
(`fs.Drain` / `new Drain()`: `with drain.work():` refuses new work once a stop began);
|
|
181
182
|
interrupted work resumes on the next start. Log through `RotatingLog` (5 × 5 MB, 0600)
|
|
182
183
|
and call `cap_stdout_log` once at start.
|
|
@@ -186,18 +187,18 @@ in Python; jobs live in `fabric_interop.JobStore(dirs["data"] / "jobs")`, create
|
|
|
186
187
|
the lock like every other piece of state. Add `"mcp": {"path": "/mcp", "transport":
|
|
187
188
|
"streamable-http", "capabilities": [...]}` to the well-known surfaces, and point the
|
|
188
189
|
descriptor's `fabricManifest` at a manifest whose service key names this
|
|
189
|
-
`<id>.<instance
|
|
190
|
+
`<id>.<instance>`; `sample_service.py register` shows both.
|
|
190
191
|
|
|
191
|
-
## Step 4
|
|
192
|
+
## Step 4: install it
|
|
192
193
|
|
|
193
194
|
The installer, not the service, owns the plist and the descriptor. Sequence:
|
|
194
195
|
|
|
195
|
-
1. `write_descriptor(descriptor)
|
|
196
|
-
claims. A preview or branch copy is a second **instance**, never a second id
|
|
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
|
|
197
198
|
one more service the operator sees, probes and gets notified by. Verify a release with its
|
|
198
199
|
own doctor or self-check before it replaces `default`; a temporary instance is uninstalled
|
|
199
200
|
(`launchd_uninstall`, `remove_descriptor`) as soon as its check is done, not left running.
|
|
200
|
-
2. `launchd_plist(...)` then `launchd_install(...)
|
|
201
|
+
2. `launchd_plist(...)` then `launchd_install(...)`: writes and lints the plist,
|
|
201
202
|
`bootout` and waits for the unload, `bootstrap` with retries on the transient I/O
|
|
202
203
|
error, then polls the well-known document until it answers with **this** identity.
|
|
203
204
|
A label the operator disabled stays disabled: only a first install enables.
|
|
@@ -216,7 +217,7 @@ rewrites the plist and restarts. Read [the lifecycle reference](references/lifec
|
|
|
216
217
|
for the plist fields, the release layout, log rotation, behaving under a host lifecycle broker
|
|
217
218
|
and the Linux and Windows supervisors.
|
|
218
219
|
|
|
219
|
-
## Step 5
|
|
220
|
+
## Step 5: the dashboard and the events
|
|
220
221
|
|
|
221
222
|
The dashboard is a same-origin page: no inline script, strict CSP, polling that pauses
|
|
222
223
|
while the operator types or a dialog is open, one panel's failure never blanks the
|
|
@@ -234,10 +235,10 @@ and declare it with `extensions=fs.dashboard_extension()`. Read
|
|
|
234
235
|
declaration and how to upgrade a dashboard built before the kit: an upgrade you may make yourself,
|
|
235
236
|
which the plugin's session-start notice offers in a repository that owns the service.
|
|
236
237
|
|
|
237
|
-
The events feed is a **view over the log you already keep**
|
|
238
|
-
journal
|
|
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
|
|
239
240
|
`notify: true` only when the operator must decide, or something failed or degrades their
|
|
240
|
-
work
|
|
241
|
+
work, once per episode, with a `subject` and a `link` to the page that resolves it. A
|
|
241
242
|
question's kind says so (`*.awaiting_*`, `*.approval_*`, `human_step.opened`). The service
|
|
242
243
|
raises no banners of its own: the host is the one channel. Read
|
|
243
244
|
[the events reference](references/events-and-notifications.md) for mapping an existing
|
|
@@ -252,9 +253,9 @@ A service whose store holds what the operator decided keeps **settings backups**
|
|
|
252
253
|
directory, restores only on a fresh database and never overwrites. Read
|
|
253
254
|
[the settings backups reference](references/settings-backups.md).
|
|
254
255
|
|
|
255
|
-
## Step 6
|
|
256
|
+
## Step 6: verify
|
|
256
257
|
|
|
257
|
-
Run the probe against the live service
|
|
258
|
+
Run the probe against the live service: it reads the descriptor, then checks every
|
|
258
259
|
rule it can reach and says which it could not:
|
|
259
260
|
|
|
260
261
|
```bash
|
|
@@ -267,7 +268,7 @@ events auth and shape, single-use login, state outside code, instance lock, plis
|
|
|
267
268
|
launchd pid equals answering pid, `dashboard.declared` (ED-9), and the `interop.*` rules:
|
|
268
269
|
manifest link, capability list, tools equal to the manifest, job tools, unknown job, trace
|
|
269
270
|
propagation, event trace pairs, and `board.responder` for a service that declares the project board) and exits 1 on
|
|
270
|
-
any `FAIL`. A `NOT_RUN` is not a pass
|
|
271
|
+
any `FAIL`. A `NOT_RUN` is not a pass;
|
|
271
272
|
name it in the report. A service with a dashboard also runs the layout probe,
|
|
272
273
|
`node <skill-dir>/scripts/check_dashboard_layout.mjs --service <id>` (WebKit at 360, 480, 768
|
|
273
274
|
and 1280 px; needs Playwright, else `NOT_RUN`).
|
|
@@ -276,7 +277,7 @@ Then prove the lock: start a second copy by hand against the same data directory
|
|
|
276
277
|
must exit 75 while the first keeps serving. Prove recovery: `kill -9` the launchd pid;
|
|
277
278
|
the well-known document must answer again with a new pid within about 15 seconds.
|
|
278
279
|
|
|
279
|
-
## Packing and signing it
|
|
280
|
+
## Packing and signing it: `fabric-package/1`
|
|
280
281
|
|
|
281
282
|
To hand an agent to another machine or an organization, pack it as one folder (contract DEC-0050, DEC-0051). Write the
|
|
282
283
|
author's `fabric.package.json` (the descriptive fields; for an agent `resultSignal` and `evals` with the receipt of the
|
|
@@ -312,11 +313,11 @@ first commit:
|
|
|
312
313
|
org-index `scripts/check_format.py` reports 0 findings for it before it is called done. **An agent
|
|
313
314
|
someone builds for themselves is not a PassionCode.ai repository:** its licence is its owner's
|
|
314
315
|
choice, nothing about it is published or listed by the organization, and none of these files is
|
|
315
|
-
required of it
|
|
316
|
+
required of it, though the verified MCP quick start is still how anyone learns to drive it.
|
|
316
317
|
|
|
317
|
-
## Online services
|
|
318
|
+
## Online services: the remote placement
|
|
318
319
|
|
|
319
|
-
An agent or a dashboard that runs online
|
|
320
|
+
An agent or a dashboard that runs online (on a platform, a server, a hosted app) becomes a
|
|
320
321
|
Fabric service with the same four routes and one descriptor on the operator's computer
|
|
321
322
|
(`placement: "remote"`, DEC-0019). Nothing about launchd, the lock or loopback applies; three
|
|
322
323
|
things change and the kits implement each:
|
|
@@ -327,7 +328,7 @@ things change and the kits implement each:
|
|
|
327
328
|
| Well-known | only for the token; otherwise `401` with an **empty** body | `wellKnownAllowed('remote', …)` / `well_known_allowed` |
|
|
328
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 })` |
|
|
329
330
|
|
|
330
|
-
1. **Serve the four routes** in the app that already exists
|
|
331
|
+
1. **Serve the four routes** in the app that already exists, not beside it. The complete worked
|
|
331
332
|
example is [`scripts/sample-remote-service.mjs`](scripts/sample-remote-service.mjs): it runs
|
|
332
333
|
with its own TLS or behind a platform router.
|
|
333
334
|
2. **Secrets live on the platform:** the service token and the session key (32 bytes) are
|
|
@@ -335,7 +336,7 @@ things change and the kits implement each:
|
|
|
335
336
|
remote service needs is issued and kept in Project Observatory, pushed to the platform, and
|
|
336
337
|
the movement recorded with `vault.py moved --at <provider>`, so the platform's copy is
|
|
337
338
|
known rather than invisible.
|
|
338
|
-
3. **Register it on the operator's computer
|
|
339
|
+
3. **Register it on the operator's computer**, the installer side, run there:
|
|
339
340
|
`registerRemote({ id, name, origin, token })` / `register_remote(...)` writes the token file
|
|
340
341
|
(0600) and the descriptor; pass the token from a file or stdin, never in argv. Public names
|
|
341
342
|
only in public artifacts: a private service is registered by a local descriptor and nowhere
|
|
@@ -349,7 +350,7 @@ behaviour a host shows, rotation, a multi-process platform, and what a host will
|
|
|
349
350
|
|
|
350
351
|
## Migrating an existing service
|
|
351
352
|
|
|
352
|
-
Read [the migration reference](references/migrating-a-service.md)
|
|
353
|
+
Read [the migration reference](references/migrating-a-service.md): the order of
|
|
353
354
|
changes that keeps the service answering throughout, and what each existing service on
|
|
354
355
|
this estate needs.
|
|
355
356
|
|
|
@@ -366,14 +367,14 @@ this estate needs.
|
|
|
366
367
|
against [the protocol reference](references/protocol.md); the probe is the judge.
|
|
367
368
|
- **No contract checkout:** the protocol reference is pinned to the extension commit
|
|
368
369
|
in this skill's metadata; do not reconstruct fields from memory.
|
|
369
|
-
- **Fabric Dashboards not installed:** nothing changes
|
|
370
|
+
- **Fabric Dashboards not installed:** nothing changes; the service is complete
|
|
370
371
|
without a host; the descriptor waits for one.
|
|
371
372
|
|
|
372
373
|
## Gotchas
|
|
373
374
|
|
|
374
375
|
- `lsof` shows `*:<port>` or `0.0.0.0` → the bind is wrong even if the Host check works.
|
|
375
376
|
- A health probe that only checks HTTP 200 accepts any program on the port. Compare
|
|
376
|
-
`service.id` and `service.instance
|
|
377
|
+
`service.id` and `service.instance`: two services here once defaulted to ports
|
|
377
378
|
another service already held.
|
|
378
379
|
- `launchctl bootstrap` right after `bootout` fails with I/O error 5 until the unload
|
|
379
380
|
finishes; wait, then retry.
|
|
@@ -396,7 +397,7 @@ the probe table verbatim with every `NOT_RUN` explained; the lock and kill-9 res
|
|
|
396
397
|
with pids; and the one next command. Never call a service conformant while the probe
|
|
397
398
|
reports a `FAIL`.
|
|
398
399
|
|
|
399
|
-
## Dashboard handoff
|
|
400
|
+
## Dashboard handoff: also for consumers
|
|
400
401
|
|
|
401
402
|
When handing a registered service dashboard to a person, or writing the generated
|
|
402
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"
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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 */
|