@passioncode-ai/fabric-agent-adapter 0.80.2 → 0.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +157 -0
- package/README.md +18 -5
- package/SECURITY.md +25 -8
- package/bin/fabric-agent-adapter.js +24 -1
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +6 -4
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +16 -3
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/source-and-instance.md +44 -7
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +116 -4
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/check_dashboard_link.py +33 -3
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_secrets.py +257 -10
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_check.py +57 -77
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_restart.py +56 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_tree.py +899 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/new_agent.py +308 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +7 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +23 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +4 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +15 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +16 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +5 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +28 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +4 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +47 -10
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +10 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +31 -8
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_layout.mjs +21 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_link.py +33 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +19 -28
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_channel_agent.py +9 -6
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py +146 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +2 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +79 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-holds.mjs +269 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +64 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-hub.mjs +16 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +73 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +98 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-peer-owner.mjs +89 -22
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +39 -6
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +8 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +76 -11
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +8 -153
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +86 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_holds.py +324 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +34 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_hub.py +35 -17
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +77 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +103 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py +156 -133
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py +257 -10
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +6 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +64 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +246 -24
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +16 -6
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agent-templates.md +44 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/communication-agent-template.md +19 -328
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +16 -3
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/models-and-providers.md +1 -1
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/new-agent.md +42 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/source-and-instance.md +44 -7
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/access.schema.json +50 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/connections.schema.json +23 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/data-rooms.schema.json +74 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/manifest.schema.json +170 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/template-header.schema.json +25 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/check_dashboard_link.py +33 -3
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/template_check.py +491 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/CHANGELOG.md +7 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/TEMPLATE.md +347 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/access.json +24 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/assembly.md +15 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/checks/acceptance.md +17 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/connections.json +29 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/data-rooms.json +9 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/manifest.json +32 -0
- package/plugins/fabric-agent-adapter/skills/observing-products/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +2 -2
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/on-demand-session.md +16 -8
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +46 -31
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_cli.py +18 -16
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +23 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,162 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.82.0 (2026-11-12)
|
|
4
|
+
|
|
5
|
+
Wave 4 of the backlog sweep of 2026-11-12. The contract pin stays at `93e7db16` (`v0.1.0+2026-11-08.1`). Kit modules
|
|
6
|
+
change: `fabric_secrets`, `fabric_connections`, `fabric_peer_owner` (`1.2.0+kit.6`), `fabric_descriptor`,
|
|
7
|
+
`fabric_holds`, `fabric_hub`, `fabric_lock`, the facade `fabric_service`, `fabric-delegation.mjs`, and their Node twins;
|
|
8
|
+
dashboard kit 1.1.7.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **working-with-fabric answers a board request as contract DEC-0152 SA-6 says** (FAA-311): a session reads the
|
|
13
|
+
capability's slot in `com.status` first; at an `active` slot, or an enroll refused `fenced`, it leaves the request to
|
|
14
|
+
that holder, sends nothing and asks no one; it declines only at a slot `absent` at generation 0, and asks the operator
|
|
15
|
+
with `fabric_question_ask` after any refusal that is not retryable. A session without the slot does no work on a
|
|
16
|
+
request and gives it no state. The exit contract, the preamble, `SKILL.md` and the references say so, the exit
|
|
17
|
+
contract within Hermes' 4000 characters (3996).
|
|
18
|
+
- **The peer owner reads DEC-0155's restricted table** (FAA-312): a `netstat` that fails or exits non-zero, a macOS
|
|
19
|
+
table with no row of another uid (sysctl) or process (netstat), and one without the reader's own connection read
|
|
20
|
+
`table-restricted` (RT-1); Linux and Windows keep `no-row`. Under a restricted table a listener is this account's only
|
|
21
|
+
on exactly `127.0.0.1` (RT-4). The launchd vouch takes only a listen on exactly `127.0.0.1` (RT-3), never the IPv4
|
|
22
|
+
wildcard or `::1`, and nothing from a set-uid reader: the kit's wildcard departure ends. `PEER_OWNER_VERSION` is
|
|
23
|
+
`1.2.0+kit.6`.
|
|
24
|
+
- **The kit's hub locator answers a pid another OS account holds as the session hooks do** (FAA-304, after FAA-254):
|
|
25
|
+
`pid_alive` / `pidAlive` give None / null and `locate_hub` / `locateHub` refuse with `not-a-hub`, retryable, "not
|
|
26
|
+
verified", never `not-running`.
|
|
27
|
+
- **`fabric_secrets.secret_url` refuses a URL whose host or port `new URL` refuses** (FAA-309), as `secretUrl` does:
|
|
28
|
+
the WHATWG host reading and the IDNA tables of FAA-98 move into `fabric_secrets` (`fabric_connections` imports them;
|
|
29
|
+
new `url_refused`). `repository_credential` still reads a repository's parameters whatever its host.
|
|
30
|
+
- **One-pass JWT reading** (FAA-313): `has_jwt` / `jwt_spans` (Node `hasJwt` / `jwtSpans`), the same answers in linear
|
|
31
|
+
time; `secret_value`, `secret_argument`, the channel-agent check and `fabric_source_tree` use it.
|
|
32
|
+
- **The holds twins agree on whitespace** (FAA-316): both squash a `statusMessage` with one ECMAScript class, so
|
|
33
|
+
U+001C, U+0085 and U+FEFF read the same; four vectors in `test/fixtures/holds/waiting-vectors.json`.
|
|
34
|
+
- **The probe's `lifecycle.one-copy` finds a LaunchDaemon's leftover LaunchAgent** (FAA-317) in its `UserName`'s
|
|
35
|
+
`gui/<uid>` first, then in the probe's own; `in_launch_daemons` is `fabric_supervisors._in_daemons`, imported.
|
|
36
|
+
- **Dashboard kit 1.1.7** (FAA-314): `fabric-button.js` reads credentials with DEC-0151's `SECRET_VALUE`, held to the
|
|
37
|
+
contract's `secretValue` and `credentialName` vectors.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **A copy holding the instance lock stops when its lock file is replaced** (FAA-303, the 0.79.0 seam reading). On
|
|
42
|
+
macOS `flock` and `O_EXLOCK` lock an inode, so a data folder swapped under a running copy let a second copy lock the
|
|
43
|
+
new file and start. `hold_single_instance` / `holdSingleInstance` now start `InstanceLock.watch` /
|
|
44
|
+
`InstanceLock#watch` there: every `LOCK_WATCH_SECONDS` (2 s) it compares the locked inode with the file at the path,
|
|
45
|
+
and once the path names another file the copy exits 75 with one sentence naming the path (`lost_lock_message` /
|
|
46
|
+
`lostLockMessage`; `on_lost` / `onLost` replaces that reaction). The two copies overlap for at most one interval.
|
|
47
|
+
Linux and Windows keep their path-keyed name and are unchanged.
|
|
48
|
+
- **Tests that failed under load** (FAA-308): the linear-time tests for `raw_values` and the minified JSON line read the
|
|
49
|
+
thread's CPU time, not the wall clock (kept on Windows), so a load near 110 no longer fails them, while a quadratic
|
|
50
|
+
implementation still does; the board sample's probe test lets `well-known.fast`, which times the machine, go either
|
|
51
|
+
way, as `test_probe_interop` does.
|
|
52
|
+
- A flaky test drew a SAS signature without a digit about once in 1500 runs, a shape the long-run rule excludes by its
|
|
53
|
+
definition; it now draws one in the rule's shape.
|
|
54
|
+
|
|
55
|
+
- **What the 0.82.0 seam reading found, fixed before the release**: Python's credential readers
|
|
56
|
+
(`fabric_secrets.url_refused` and its copy, `fabric_connections._whatwg_parts`, `check_service_channel_agent.url_parts`)
|
|
57
|
+
refuse a URL whose empty host is followed by `:`, with or without a port, as `new URL` does (`foo://:/?token=...`;
|
|
58
|
+
four shared vectors in both suites). `adapt_project`'s LC-21 gates read a stored URL's credential without the host
|
|
59
|
+
check, so a password in a manifest or `plugin.json` URL is found whatever its host. Every other reader of the JWT rule
|
|
60
|
+
reads it in one pass too (`fabric_source_check`, `fabric_connections` and its Node twin, the three
|
|
61
|
+
`check_dashboard_link.py` copies, `fabric-button.js`). Python `pid_alive` on Windows (`fabric_hub`,
|
|
62
|
+
`fabric_session_env`) answers None when OpenProcess is refused with access denied, as Node's EPERM does. The README
|
|
63
|
+
states the preamble's request rule; the exit contract's closing checkpoint names its `status` again (done if
|
|
64
|
+
completed, blocked if failed_known); the hub and HTTP docstrings say a missing row on macOS is `table-restricted`.
|
|
65
|
+
New rows FAA-320 to FAA-323.
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- **`fabric_peer_owner.py listener <port> [--json]`** and **`fabric-peer-owner.mjs listener <port>`** print the
|
|
70
|
+
listener's kind (FAA-315): the route for the dashboard link gate's `listener_owner`, named in the three
|
|
71
|
+
`dashboard-links.md`.
|
|
72
|
+
|
|
73
|
+
### Documented
|
|
74
|
+
|
|
75
|
+
- On a host with a restricted socket table the dashboard layout probe measures nothing: every rule `NOT_RUN`, exit 3
|
|
76
|
+
(FAA-318). It does not vouch by the service's pid, which DEC-0155 RT-3 reserves for the caller that started it.
|
|
77
|
+
- FAA-292's decision: RT-2 through libproc waits for an L0 module of its own, as `fabric_peer_owner.py` is at the
|
|
78
|
+
1000-line cap (`docs/evidence/specs/2026-11-12-faa-292-libproc-decision.md`); the row stays open.
|
|
79
|
+
- `fabric-delegation.mjs` carries the `<https>` legend; `HTTPS_LEGEND_PENDING` in `test/validate.py` is empty (FAA-306).
|
|
80
|
+
|
|
81
|
+
## 0.81.0 (2026-11-12)
|
|
82
|
+
|
|
83
|
+
Wave 3 of the backlog sweep of 2026-11-12. **The contract pin moves to `93e7db16` (`v0.1.0+2026-11-08.1`)**: DEC-0149
|
|
84
|
+
(`fabric-source/1`), CT-254 (HA-2's Linux source, the hybrid the kit already read), DEC-0151, DEC-0152, DEC-0155.
|
|
85
|
+
Bundles pinned at `18f8d487` stay valid (FAA-258; impact map `docs/evidence/specs/2026-11-12-faa-258-repin-93e7db16-impact-map.md`).
|
|
86
|
+
New kit modules: `fabric_holds` and `fabric-holds.mjs`. Kit modules change: `fabric_secrets`, `fabric_protocols`,
|
|
87
|
+
`fabric_peer_owner` (`1.2.0+kit.5`), `fabric_package`, `fabric_descriptor`, `fabric_http`, `fabric_supervisors`, the
|
|
88
|
+
facade `fabric_service`, and their Node twins.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- **`npx @passioncode-ai/fabric-agent-adapter new <folder> --id <agent-id> [--profile ...] [--service]`** (North Star G21,
|
|
93
|
+
FAA-270), and `new_agent.py` behind it: one command creates an agent project with the contract built in: the bundle
|
|
94
|
+
pinned at the contract, `fabric.source.json`, a placement guard reading Observatory's `observatory-placement/1` record
|
|
95
|
+
with its tests, and with `--service` the service kit's sample (its modules copied by `fabric_kit.py install`).
|
|
96
|
+
Idempotent, refuses a folder holding other files without `--force`, JSON last. It needs Python 3.9 or later on the
|
|
97
|
+
machine. Turning a sentence into an agent (`new "<sentence>"`, `test`) stays FAA-26, waiting on Fabric's
|
|
98
|
+
`fabric.agent.create`.
|
|
99
|
+
- **`fabric.source.json` (DEC-0149, `fabric-source/1`)** (FAA-261): `fabric_source_tree.py` ports the contract's source
|
|
100
|
+
rules and matches all 140 of its vendored vectors; `fabric_source_check.py check` reads the source a manifest names,
|
|
101
|
+
by path, line and column, never the value; `adapt_project.py source` lays the manifest down with the kit's slots
|
|
102
|
+
(`PUBLISHER_URI` behind the `createdBy` sentinel, `PLACEMENT_RECORD`, and for a service `SUPERVISOR_LABEL` and
|
|
103
|
+
`SERVICE_PORT`; FAA-188's part 2); `pack` writes `secrets[]` and `state[]` from the slots, and FAC-SEM-160 refuses a
|
|
104
|
+
package that differs.
|
|
105
|
+
- **Work held by a service's own limits** (FAA-298): new kit modules `fabric_holds` and `fabric-holds.mjs` (L3). A held
|
|
106
|
+
job says why it waits in `statusMessage` with the contract's pause grammar (the job schema is closed); the operator gets
|
|
107
|
+
one push per hold, and the answer is recorded as a scoped lift that falls back when its window ends; a new probe rule
|
|
108
|
+
`limits.holds`.
|
|
109
|
+
- **Agent template folders** (FAA-265): five JSON Schemas and `template_check.py` in creating-fabric-agents; the
|
|
110
|
+
communication agent template moved into `templates/communication-agent/` with its manifest, connections, access, data
|
|
111
|
+
rooms, checks, assembly and changelog; `validate.py` checks every shipped template folder.
|
|
112
|
+
|
|
113
|
+
### Changed
|
|
114
|
+
|
|
115
|
+
- The probe's `limits.holds` reads a service that declares limits but does not use `fabric_holds` as NOT_RUN with a
|
|
116
|
+
migration note, not FAIL, and counts only code files (a vendored `check_service_rules.py` and docs naming `HoldBook`
|
|
117
|
+
no longer pass it). `LoopbackHTTPServer` and `loopbackServer` read the socket table only for a loopback peer: a peer
|
|
118
|
+
at another address (a `0.0.0.0` bind) is served with no owner under `refuse` and `strict` (the 0.81.0 seam reading).
|
|
119
|
+
- **A kit service refuses a loopback peer of another OS account before it reads the request** (DEC-0154 HA-2 and HA-3,
|
|
120
|
+
FAA-227): `LoopbackHTTPServer` takes `peer_check` and Node's new `loopbackServer(httpServer, {peerCheck})` holds each
|
|
121
|
+
connection paused until the check passes; `refuse` (the default) closes another account's peer and serves the rest,
|
|
122
|
+
`strict` also refuses an owner it cannot tell, `off` reads nothing.
|
|
123
|
+
- `fabric_http` and `fabric-http.mjs` check plain http that reaches loopback by its connected address, `insecure=True` and
|
|
124
|
+
a loopback proxy included (FAA-260). The probe times the well-known answer after the owner check, fails a deeply
|
|
125
|
+
nested body cleanly, compares port claims as ports (`:08080` is `:8080`), names the listener on a failed connect, and
|
|
126
|
+
no longer stops on a well-known body that is not an object; the layout probe opens a loopback page only after its
|
|
127
|
+
listener is this account's (FAA-260).
|
|
128
|
+
- The dashboard link gate opens a raw loopback address in a browser only when `listener_owner` is `this-account` as
|
|
129
|
+
well as the host `not_installed` (FAA-251).
|
|
130
|
+
- LaunchDaemon installs and uninstalls refuse contradicting domains, leftover LaunchAgents, another label's plist and an
|
|
131
|
+
unparseable or binary plist, and remove a plist a failed bootstrap wrote; the probe fails a LaunchDaemon without
|
|
132
|
+
`UserName`, with a `~` command, or loaded in both domains (FAA-286).
|
|
133
|
+
- **The kit's credential detector is the contract's DEC-0151 `SECRET_VALUE`**, in both twins and the three dashboard
|
|
134
|
+
link checkers: a provider prefix counts only in its canonical case and after a boundary; an `sk-` key needs a digit and
|
|
135
|
+
an upper-case letter (16 characters or more) or a digit (32 or more), so `SK-...`, `sk-learn-...` and an `sk-` inside a
|
|
136
|
+
word are no longer keys. Repository names keep their own boundary-free key shapes, as DEC-0151 asks (FAA-258).
|
|
137
|
+
- `fabric_protocols` lists `fabric-source/1`; `fabric_peer_owner` is `1.2.0+kit.5`, one version line with Observatory's
|
|
138
|
+
1.2.0, the Linux reading unchanged (FAA-258).
|
|
139
|
+
- Every vendored contract vector is regenerated at the new pin with the contract's own generators;
|
|
140
|
+
`make_load_vectors.mjs` reads the pin from the lock file. SECURITY.md, lifecycle.md and protocol.md name DEC-0155 RT-3
|
|
141
|
+
for the vouch; SA-6 (DEC-0152) is the accepted board rule (FAA-258).
|
|
142
|
+
|
|
143
|
+
### Fixed
|
|
144
|
+
|
|
145
|
+
- `fabric_source_check.py` refuses a copy without `fabric_source_tree.py` with exit 2 and the file's name, not a
|
|
146
|
+
traceback and exit 1; `pack` (both kits) refuses by name a hand-written `secrets[]` naming a secret `fabric.source.json`
|
|
147
|
+
has no slot for, instead of dropping it (the 0.81.0 seam reading). The Windows job runs the loopback peer check.
|
|
148
|
+
|
|
149
|
+
### Upgrading
|
|
150
|
+
|
|
151
|
+
- A door that gave T0 because `strict` served the peer must also check that the peer's owner is named
|
|
152
|
+
(`peer_owner()` / `connectionOwner`): a peer off loopback has none and is T2. A folder whose `fabric.package.json`
|
|
153
|
+
names secrets its `fabric.source.json` lacks fails `pack` until they are added as `secret` slots.
|
|
154
|
+
- A service that serves loopback HTTP keeps serving its own account's callers; pass `peer_check="strict"` to refuse an
|
|
155
|
+
owner the table cannot tell. A caller of the dashboard link gate passes `listener_owner`. An outside test that runs
|
|
156
|
+
this checkout's probe needs a readable socket table.
|
|
157
|
+
- A service that vendors the kit takes the changed `fabric_secrets`, `fabric_protocols` and `fabric_peer_owner` with
|
|
158
|
+
`fabric_kit.py install`. A string the 0.80 detector called a key may no longer be one (see Changed).
|
|
159
|
+
|
|
3
160
|
## 0.80.2 (2026-11-12)
|
|
4
161
|
|
|
5
162
|
0.80.1 was tagged and never published: its `windows` job (run 43212508702) failed one test, so `release` and `publish`
|
package/README.md
CHANGED
|
@@ -23,10 +23,12 @@ The skills are `adapting-projects-to-fabric`, `creating-fabric-agents`,
|
|
|
23
23
|
`working-with-fabric` is for the other side: a coding agent (Claude Code, Codex, Kimi Code, Kilo, Hermes) opened in
|
|
24
24
|
a terminal that works in a project through Fabric. It finds Fabric (`hub.json`, its `pid`), has the machine's
|
|
25
25
|
lifecycle broker start it when it is down, registers `fabric-mcp` once with no secret, calls `fabric_whoami`
|
|
26
|
-
first, reads the project board (`com.status`, `com.list`, `com.read_ack` only what was read)
|
|
27
|
-
Project in the same turn
|
|
26
|
+
first, reads the project board (`com.status`, `com.list`, `com.read_ack` only what was read): an announcement or
|
|
27
|
+
question waiting on its Project gets its state in the same turn (the result later), and a request to its Project is
|
|
28
|
+
read through its capability's slot in `com.status` (`active` is left to its holder and nobody is asked; otherwise
|
|
29
|
+
`com.enroll`, and only the slot's holder gives the request its state; before Fabric 0.3.17 a run Fabric starts
|
|
28
30
|
declines a request no session can take and the asker resends, and from 0.3.17 the session's own Project is granted
|
|
29
|
-
`board.respond` at `com.enroll`, CO-506)
|
|
31
|
+
`board.respond` at `com.enroll`, CO-506). It asks other
|
|
30
32
|
Projects only through `com.submit`, asks who is working on what and claims its task before it starts
|
|
31
33
|
(`fabric_work_list`, `fabric_work_claim`, Fabric v0.3.5 and later), links tasks to backlog rows instead of copying them, and
|
|
32
34
|
releases at the end (`fabric_work_release`). `scripts/fabric_session.py status` prints where Fabric stands and one
|
|
@@ -152,7 +154,9 @@ For provider bundles the adapting skill helps an agent author:
|
|
|
152
154
|
admission, and project binding;
|
|
153
155
|
- keep the agent's source apart from its instance data, with `scripts/fabric_source_check.py check`, which reports a
|
|
154
156
|
home path, a credential-shaped value or a string from the owner's list by path, line and kind and never repeats it
|
|
155
|
-
(FAA-188).
|
|
157
|
+
(FAA-188); under the source manifest `fabric.source.json` (contract DEC-0149, `fabric-source/1`, which
|
|
158
|
+
`scripts/adapt_project.py source` proposes) it reads the source the manifest names with the contract's tree check
|
|
159
|
+
(FAA-261), and `pack` writes the package's `secrets[]` and `state[]` from its slots.
|
|
156
160
|
|
|
157
161
|
The skill never treats generated files as admission. Fabric contract `0.1.0` does not
|
|
158
162
|
yet ship the host registry/runtime needed to connect and authorize a live provider.
|
|
@@ -169,6 +173,7 @@ then restart your agents. Alone, without any account:
|
|
|
169
173
|
npx @passioncode-ai/fabric-agent-adapter # installs every skill into the agents hub ~/.agents/skills
|
|
170
174
|
npx @passioncode-ai/fabric-agent-adapter --prune-shadow # remove ~/.claude/skills copies that shadow the plugin
|
|
171
175
|
npx @passioncode-ai/fabric-agent-adapter --force # update a copy already in the hub (a launcher link is never replaced)
|
|
176
|
+
npx @passioncode-ai/fabric-agent-adapter new ./example-agent --id example-agent [--service] # a new agent project, contract built in
|
|
172
177
|
```
|
|
173
178
|
|
|
174
179
|
A copy already in the hub is left alone unless `--force` is given; with it, the new copy is built beside the old one
|
|
@@ -300,8 +305,16 @@ python3 "$SKILL_DIR/scripts/adapt_project.py" scaffold /path/to/project \
|
|
|
300
305
|
--effect none
|
|
301
306
|
python3 "$SKILL_DIR/scripts/adapt_project.py" check /path/to/project \
|
|
302
307
|
--contract /path/to/fabric-agent-contract --json
|
|
308
|
+
python3 "$SKILL_DIR/scripts/adapt_project.py" source /path/to/project --dry-run # propose fabric.source.json
|
|
309
|
+
python3 "$SKILL_DIR/scripts/new_agent.py" ./example-agent --id example-agent # what `npx ... new` runs
|
|
303
310
|
```
|
|
304
311
|
|
|
312
|
+
`new` (FAA-270) writes a new agent project from the kit's template: the provider bundle pinned to the contract,
|
|
313
|
+
`fabric.source.json`, the placement guard with its tests, and with `--service` the service kit's sample; a repeat
|
|
314
|
+
changes nothing, a folder holding other files is refused without `--force`, and the last line is JSON
|
|
315
|
+
([new-agent.md](plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/new-agent.md)). Inferring the agent
|
|
316
|
+
from a sentence and running its evals (`new "<sentence>"`, `test`) stay with FAA-26.
|
|
317
|
+
|
|
305
318
|
Pack, sign and verify an agent as a `fabric-package/1` folder (contract DEC-0050, DEC-0051; nothing is written without
|
|
306
319
|
`--apply`, and the key file is the person's, never made or kept here). First check the checkout, then make the clean
|
|
307
320
|
copy [the package reference](plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md)
|
|
@@ -330,7 +343,7 @@ Scaffolding is non-destructive by default. It writes only the paths declared in
|
|
|
330
343
|
The default pin for new bundles is [`fabric-contract.lock.json`](fabric-contract.lock.json):
|
|
331
344
|
|
|
332
345
|
- version: `0.1.0`
|
|
333
|
-
- commit: `
|
|
346
|
+
- commit: `93e7db164c7829e2783b4b7705c4113bb5201131`
|
|
334
347
|
|
|
335
348
|
Every other mention of the default contract revision (this section, the skills' metadata, the
|
|
336
349
|
skill card, `adapt_project.py`) must equal it; `python3 test/validate.py` fails a tree
|
package/SECURITY.md
CHANGED
|
@@ -31,7 +31,7 @@ bounded and non-publishing until explicit scoped grants exist in a project bindi
|
|
|
31
31
|
there with an explicit `domain="gui"`, not refused yet, FAA-286 item 21); the job runs as the account its `UserName`
|
|
32
32
|
names. The installer accepts the job's answer only on a connection launchd's own job accepted
|
|
33
33
|
(its pid from `launchctl print system/<label>`) or, where the socket table is restricted, on a port that pid listens
|
|
34
|
-
on (`lsof -p`, the weaker vouch below,
|
|
34
|
+
on (`lsof -p`, the weaker vouch below, DEC-0155 RT-3). The
|
|
35
35
|
token is readable by any process of the same user; the protocol defends against web pages
|
|
36
36
|
and mistakes, not against hostile local code.
|
|
37
37
|
- The kits' connectors (`fabric_http`, `fabric_openrouter` and their Node twins) reach the
|
|
@@ -48,25 +48,42 @@ bounded and non-publishing until explicit scoped grants exist in a project bindi
|
|
|
48
48
|
restricted table, to a port that pid listens on there (the weaker vouch below): a departure from the pinned HA-2 and
|
|
49
49
|
the contract's later RT-3, accepted in principle by the contract owner as DEC-0161 (proposed; the restricted-table vouch
|
|
50
50
|
included) and kept as a departure until the next repin (FAA-288). They read, never change:
|
|
51
|
-
macOS `sysctl net.inet.tcp.pcblist_n` in the process
|
|
51
|
+
macOS `sysctl net.inet.tcp.pcblist_n` in the process (the TCP table in the record layout `netstat -anv` reads;
|
|
52
|
+
the pinned HA-2 table names `netstat -anv` and `pcblist64`, an older layout of the same table), or the programs `/usr/sbin/netstat
|
|
52
53
|
-anv -p tcp` and `/bin/ps -o uid= -p <pid>` (the Node twin always); Linux
|
|
53
54
|
`/proc/net/tcp` and `/proc/net/tcp6`; Windows `GetExtendedTcpTable` and the process
|
|
54
|
-
token (Python), or `netstat -ano
|
|
55
|
-
|
|
55
|
+
token (Python), or `netstat -ano` and one PowerShell `GetOwnerSid` query per new connection,
|
|
56
|
+
with `whoami /user` once a process (Node). On macOS the Python reader calibrates once per process with a
|
|
56
57
|
short-lived child of its own interpreter listening on a random `127.0.0.1` port; when the
|
|
57
58
|
table is restricted (macOS 27.2, FAA-267) the launchd installers also run `/usr/sbin/lsof
|
|
58
59
|
-nP -a -p <pid> -i4TCP -sTCP:LISTEN -Fn` on their own job's pid. That vouch shows the job listens on the port, not that it accepted
|
|
59
|
-
the connection
|
|
60
|
+
the connection; it counts only a listen on exactly `127.0.0.1`, as the pin's DEC-0155 RT-3 asks (since FAA-312; a wildcard
|
|
61
|
+
or `::1` listener is never vouched for, and a set-uid reader vouches for nothing). A LaunchDaemon's root
|
|
60
62
|
installer runs that `lsof` and `ps -o uid=` on its job's pid before it accepts an answer, and reads, never changes, every other
|
|
61
63
|
plist in `/Library/LaunchDaemons` (to find another holder of its label, `plutil -convert xml1` for a binary one in
|
|
62
|
-
Node), `launchctl print system/<label>` and the `UserName`'s uid (`pwd`, or `id -u` in Node).
|
|
63
|
-
another account
|
|
64
|
+
Node), `launchctl print system/<label>` and the `UserName`'s uid (`pwd`, or `id -u` in Node). The kit's loopback server reads the table once per accepted
|
|
65
|
+
connection and closes a peer of another account before reading it (HA-3, FAA-227); a token-free door counts as
|
|
66
|
+
protected only under `peer_check="strict"`, which also refuses an owner it cannot tell. An MCP client (Claude Code, Codex) sends the
|
|
64
67
|
token it was registered with on every later connection without this check (the contract's
|
|
65
68
|
residue "a coding agent's bearer"): when the port may have changed hands, rotate the token
|
|
66
69
|
and re-run `mcp-register` (one written as `references/surfaces-and-auth.md` says checks the
|
|
67
70
|
listener first; the kit ships none). On Linux `/proc` names a socket's creator and
|
|
68
71
|
no pid, so a listening socket root created and handed to another account (systemd
|
|
69
|
-
socket activation with `User=`) reads as root's: a client running as root sends to it.
|
|
72
|
+
socket activation with `User=`) reads as root's: a client running as root sends to it. Such a system unit's
|
|
73
|
+
connection reads as root's until the service accepts it and as the service's account after, so two runs of the
|
|
74
|
+
probe can disagree on it (0.74.0 product reading 10).
|
|
75
|
+
- Credential-free loopback http is checked too (FAA-260 item 16, deliberate): `fabric_http` / `fabric-http.mjs` refuse
|
|
76
|
+
plain http to a loopback listener of another OS account or root (another account's Ollama, a `docker-proxy`) with
|
|
77
|
+
kind `foreign-user` whether or not the request carries a credential, because HA-2 reads nothing such a listener
|
|
78
|
+
answers as the service's, and an answer from another account's process is not this account's data. A caller that
|
|
79
|
+
means to read such a daemon says so with its own connection. With `insecure=True` a URL not spelled as loopback
|
|
80
|
+
(a hosts-file name, `0.0.0.0`, `[::ffff:127.0.0.1]`) and a request through a loopback `http_proxy` are checked by the
|
|
81
|
+
connected peer's address, so the Authorization header never reaches another account's proxy (FAA-260 items 1, 8).
|
|
82
|
+
- The layout probe (`check_dashboard_layout.mjs`) reads a raw loopback page's listener from the socket table just
|
|
83
|
+
before its headless browser opens it, the one-time login URL included, and opens nothing on another account's,
|
|
84
|
+
root's or an untellable listener (FAA-260 items 2, 14); under a restricted table (DEC-0155) that is every listener,
|
|
85
|
+
so it measures nothing there and never vouches by a pid it did not start (FAA-318). The browser then connects on its own: a listener swapped
|
|
86
|
+
between the read and the browser's connect is a residue, bounded by the login code's 120 s and single use.
|
|
70
87
|
- The agents database (FAA-275): creating-fabric-agents, adapting-projects-to-fabric, building-fabric-services and
|
|
71
88
|
working-with-fabric may send board requests to whichever Project the board lists under an `agents-db.*` capability
|
|
72
89
|
(on an organization's board, any member Project may list it), carrying only what `references/agents-database.md`
|
|
@@ -43,6 +43,11 @@ Packages (fabric-package/1):
|
|
|
43
43
|
npx @passioncode-ai/fabric-agent-adapter verify <folder> --trust <trust.json> [--countersigned]
|
|
44
44
|
check the folder and its signatures against the keys you pin
|
|
45
45
|
|
|
46
|
+
A new agent (FAA-270; needs Python 3.9 or later):
|
|
47
|
+
npx @passioncode-ai/fabric-agent-adapter new <folder> --id <agent-id> [--profile mcp|a2a|local-runner] [--service] [--force] [--json]
|
|
48
|
+
create an agent project with the contract built in: the provider bundle, fabric.source.json, the placement
|
|
49
|
+
guard and, with --service, the service kit's sample; the last line is JSON
|
|
50
|
+
|
|
46
51
|
Claude Code (recommended):
|
|
47
52
|
claude plugin marketplace add ${REPO}
|
|
48
53
|
claude plugin install ${PLUGIN_ID}
|
|
@@ -257,8 +262,26 @@ function main(argv) {
|
|
|
257
262
|
return 0;
|
|
258
263
|
}
|
|
259
264
|
|
|
265
|
+
// `new` runs the skill's own script (adapting-projects-to-fabric/scripts/new_agent.py), one implementation for the
|
|
266
|
+
// skill and this CLI, under the first Python 3 found on PATH; its output and exit code pass through unchanged.
|
|
267
|
+
function newAgent(args) {
|
|
268
|
+
const { spawnSync } = require('child_process');
|
|
269
|
+
const script = path.join(ROOT, 'plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/new_agent.py');
|
|
270
|
+
const candidates = process.platform === 'win32' ? [['py', ['-3']], ['python', []], ['python3', []]] : [['python3', []], ['python', []]];
|
|
271
|
+
for (const [command, prefix] of candidates) {
|
|
272
|
+
const probe = spawnSync(command, [...prefix, '-c', 'import sys; sys.exit(0 if sys.version_info >= (3, 9) else 1)'], { stdio: 'ignore' });
|
|
273
|
+
if (probe.status !== 0) continue;
|
|
274
|
+
const run = spawnSync(command, [...prefix, script, ...args], { stdio: 'inherit' });
|
|
275
|
+
return run.status === null ? 1 : run.status;
|
|
276
|
+
}
|
|
277
|
+
console.error('error: `new` needs Python 3.9 or later on PATH (python3, or py -3 on Windows)');
|
|
278
|
+
return 2;
|
|
279
|
+
}
|
|
280
|
+
|
|
260
281
|
const PACKAGE_COMMANDS = ['pack', 'sign', 'verify'];
|
|
261
|
-
if (
|
|
282
|
+
if (process.argv[2] === 'new') {
|
|
283
|
+
process.exitCode = newAgent(process.argv.slice(3));
|
|
284
|
+
} else if (PACKAGE_COMMANDS.includes(process.argv[2])) {
|
|
262
285
|
// The package commands live in the kit (fabric-package.mjs), one implementation for the skill and this CLI.
|
|
263
286
|
const kit = path.join(ROOT, 'plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs');
|
|
264
287
|
import(require('url').pathToFileURL(kit).href).then((m) => { process.exitCode = m.main(process.argv.slice(2)); });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/fabric-agent-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"description": "Create Fabric-compatible agents, run them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract. This package is the installer CLI.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "python3 test/validate.py && python3 -m unittest discover -s test -q && node --test 'test/*.test.mjs'"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "fabric-agent-adapter",
|
|
4
4
|
"displayName": "Fabric Agent Adapter",
|
|
5
5
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks; and put an agent on a standing watch over a product (observer mode).",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.82.0",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -9,9 +9,9 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
9
9
|
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.
|
|
10
10
|
metadata:
|
|
11
11
|
author: PassionCode.ai
|
|
12
|
-
version: "0.
|
|
12
|
+
version: "0.82.0"
|
|
13
13
|
contract-version: "0.1.0"
|
|
14
|
-
contract-commit: "
|
|
14
|
+
contract-commit: "93e7db164c7829e2783b4b7705c4113bb5201131"
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
# Adapting projects to Fabric
|
|
@@ -84,7 +84,7 @@ Use exactly:
|
|
|
84
84
|
|
|
85
85
|
- contract version `0.1.0`;
|
|
86
86
|
- repository `https://github.com/passioncode-ai/fabric-agent-contract`;
|
|
87
|
-
- commit `
|
|
87
|
+
- commit `93e7db164c7829e2783b4b7705c4113bb5201131`.
|
|
88
88
|
|
|
89
89
|
This is the default for new bundles. When checking an issued legacy bundle, preserve its
|
|
90
90
|
explicit supported lock and use that exact clean checkout. Never silently upgrade or
|
|
@@ -184,7 +184,9 @@ path, line and kind, never repeating a value, and changes nothing. Then move eac
|
|
|
184
184
|
instance value into the instance configuration outside the repository, read through a named variable with a neutral
|
|
185
185
|
default and a committed `*.example`; a key into the secret store, named only. Run the check again until it exits 0; it is a floor under the owner's review, not a secret scanner.
|
|
186
186
|
A value already committed stays in Git history: say so; a fresh history is the owner's act (no history rewrite, no
|
|
187
|
-
force-push).
|
|
187
|
+
force-push). Then lay down the source manifest, `fabric.source.json` (DEC-0149): `scripts/adapt_project.py source
|
|
188
|
+
<project-root> --dry-run` proposes it, the author narrows `include` and names each key and store as a slot, and the
|
|
189
|
+
check reads the source under it (the reference, *The source manifest*).
|
|
188
190
|
|
|
189
191
|
### 5. Make probes safe and meaningful
|
|
190
192
|
|
|
@@ -65,8 +65,8 @@ host's `open` with `fallback=never`. Never `open <url>`, `open -a Safari`,
|
|
|
65
65
|
agent's pages. A browser only when `host_status` confirms `not_installed`, and
|
|
66
66
|
a raw `http://127.0.0.1:<port>` address only after the listener on that port is
|
|
67
67
|
this OS account's (DEC-0154 PL-3 and HA-2; the adapter's `building-fabric-services/scripts/fabric_peer_owner.py`: `server_end` of a connection it opens and sends nothing on; `check_service.py <id>.<instance>` prints it as `listener.owner`): a
|
|
68
|
-
`foreign-user` listener is reported, never opened (the link gate below
|
|
69
|
-
|
|
68
|
+
`foreign-user` listener is reported, never opened (the link gate below takes
|
|
69
|
+
that owner as `listener_owner`). An installed host that failed
|
|
70
70
|
to open is reported, not replaced by HTTP. Links
|
|
71
71
|
carry no token or login code. Every completion and notification action passes
|
|
72
72
|
the Fabric Agent Adapter's link gate before delivery: `check_dashboard_link.py`
|
|
@@ -119,7 +119,20 @@ Its trusted context is supplied by the host, not by untrusted model output:
|
|
|
119
119
|
|
|
120
120
|
`native_link` must equal the resolved open_link, with an available host on the
|
|
121
121
|
viewer's device. `browser_link` must equal http_url, with confirmed not_installed,
|
|
122
|
-
if_absent policy
|
|
122
|
+
if_absent policy, the same device and `"listener_owner": "this-account"`: the kind
|
|
123
|
+
the host read for the listener on http_url's port (`fabric_peer_owner`'s
|
|
124
|
+
`this-account`, `another-account`, `system`, `unknown`, `none`, or
|
|
125
|
+
`check_service.py`'s `foreign-user`); any other, or none given, refuses the
|
|
126
|
+
browser (DEC-0154 PL-3, FAA-251). The host reads that kind right before it opens
|
|
127
|
+
the page with the adapter's
|
|
128
|
+
`python3 building-fabric-services/scripts/fabric_peer_owner.py listener <port>`
|
|
129
|
+
(or `node building-fabric-services/scripts/fabric-peer-owner.mjs listener <port>`),
|
|
130
|
+
which prints it on one line (`--json` prints the whole owner) and sends nothing
|
|
131
|
+
to the port (FAA-315). Where the socket table is restricted (macOS 27.2 for an
|
|
132
|
+
ad-hoc-signed Python or Node, DEC-0155 RT-4) only this account's listener on
|
|
133
|
+
exactly `127.0.0.1` reads `this-account`; a wildcard or `::1` bind reads
|
|
134
|
+
`unknown` (`table-restricted`), and the browser is refused. The native link does not take it: Fabric
|
|
135
|
+
Dashboards checks its own listener. Contract DEC-0123 PL-3 also allows a browser
|
|
123
136
|
on `unsupported` (a system the host does not ship for); the gate treats
|
|
124
137
|
`unsupported` as no fallback, by the operator's rule that a browser opens only on a
|
|
125
138
|
confirmed `not_installed`, and macOS never reports it (FAA-137). `remote_open` instead contains `device_id`,
|
|
@@ -7,13 +7,15 @@ first commit, so that its owner can hand the source over later without rewriting
|
|
|
7
7
|
by itself: handing over, a new remote, a push or a change of visibility stays the owner's act, each time (a personal
|
|
8
8
|
agent stays private until its owner says so about that act).
|
|
9
9
|
|
|
10
|
-
The format of a source manifest, export and import is the contract's
|
|
11
|
-
|
|
10
|
+
The format of a source manifest, export and import is the contract's: DEC-0149 (`fabric-source/1`, its `source.md`) at
|
|
11
|
+
the pin. The kit lays down `fabric.source.json` ([the source manifest](#the-source-manifest)), and the check reads the
|
|
12
|
+
source under it.
|
|
12
13
|
|
|
13
14
|
## Contents
|
|
14
15
|
|
|
15
16
|
- [The layout](#the-layout)
|
|
16
17
|
- [The data home and its kind](#the-data-home-and-its-kind)
|
|
18
|
+
- [The source manifest](#the-source-manifest)
|
|
17
19
|
- [The check](#the-check)
|
|
18
20
|
|
|
19
21
|
## The layout
|
|
@@ -42,11 +44,11 @@ on it.
|
|
|
42
44
|
- **Fixtures on neutral ids.** A test that needs a home folder, an owner or an account uses `example`, `example-agent`,
|
|
43
45
|
`owner@example.com` or a one-letter home, and a credential-shaped test value says it is synthetic
|
|
44
46
|
(`sk-test-not-a-key`) or is assembled at run time.
|
|
45
|
-
- **Two names
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
- **Two names are slots, never values (DEC-0149, FAA-188 part 2).** A service's supervisor label is the agent's own
|
|
48
|
+
name, reverse-DNS on the publisher's domain (`com.example.example-agent`), and `AGENTS.md` names it (LC-09): never the
|
|
49
|
+
owner's account or name; the label an installation runs under is its `SUPERVISOR_LABEL` slot, with its port in
|
|
50
|
+
`SERVICE_PORT`. A provider's `createdBy` names the publisher; the source keeps the scaffold's sentinel, and the
|
|
51
|
+
publisher's URI is the installation's `PUBLISHER_URI` slot, so a person's name or account is never written there.
|
|
50
52
|
|
|
51
53
|
## The data home and its kind
|
|
52
54
|
|
|
@@ -69,6 +71,41 @@ on it.
|
|
|
69
71
|
configuration and dependency folders `--every-file` reads too), each exit 0, with the owner's list or its absence recorded, until the contract's export (CT-194)
|
|
70
72
|
replaces it.
|
|
71
73
|
|
|
74
|
+
## The source manifest
|
|
75
|
+
|
|
76
|
+
`fabric.source.json` at the source's root says what is source and which slots an installation fills, never a value
|
|
77
|
+
(DEC-0149, `fabric-source/1`):
|
|
78
|
+
|
|
79
|
+
| Member | What |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `include` | the source, default deny: a file outside every entry is not source; an entry ending in `/` is a folder, no globs |
|
|
82
|
+
| `exclude` | holes in `include`, read in any letter case and Unicode form (a file an entry names only in another spelling is left out, and the check says `excluded-by-fold`) |
|
|
83
|
+
| `binaries` | the binary files that are source (an icon, a font); another binary blocks |
|
|
84
|
+
| `unchecked` | source paths that travel unread, each with its reason (synthetic test vectors, a licence naming a holder on the owner's list) |
|
|
85
|
+
| `publicAddresses` | the e-mail addresses the source may carry (a support address); another one warns |
|
|
86
|
+
| `slots` | what an installation fills, by name: `secret` (a key), `config` (a setting: a repository URL, a folder, the supervisor label, the publisher's identity), `store` (a data store, with its path in the data folder), `endpoint` (the operator's infrastructure by role) |
|
|
87
|
+
|
|
88
|
+
- **Laying it down.** A new agent gets it from `new_agent.py` (creating-fabric-agents' `references/new-agent.md`); an
|
|
89
|
+
existing project from `adapt_project.py source <project-root>` (adapting-projects-to-fabric's scripts), which proposes `include` from the
|
|
90
|
+
project's top-level entries (what Git would commit, instance data by its name left out) and names the kit's slots
|
|
91
|
+
(`PUBLISHER_URI` where a provider manifest is there, `PLACEMENT_RECORD`, and with `--service` `SUPERVISOR_LABEL` and
|
|
92
|
+
`SERVICE_PORT`); `--secret NAME:PURPOSE` and `--store NAME:PATH:PURPOSE` add the agent's own. `--dry-run` prints the
|
|
93
|
+
proposal and writes nothing; an existing manifest is the owner's and is replaced only with `--force`. The author then
|
|
94
|
+
narrows `include` to what is source.
|
|
95
|
+
- **The check under it.** When the folder it checks holds `fabric.source.json`, `fabric_source_check.py check` reads
|
|
96
|
+
the source the manifest names and reports the contract's kinds (`fabric_source_tree.py`, held to the contract's
|
|
97
|
+
vectors): blocking `home-path`, `credential`, `binary`, `nested-repository`, `instance-string`, `missing`,
|
|
98
|
+
`no-include` and the manifest's own findings (FAC-SEM-156, FAC-SEM-157); warnings `email`, `link-outside`,
|
|
99
|
+
`no-license`, `unused-exclude`, `excluded-by-fold`, each by path, line and column (UTF-16 units), never by the text
|
|
100
|
+
found. Exit 1 on a blocking finding, 0 when only warnings remain and every source file was read, 2 when one was not.
|
|
101
|
+
`.fabric-source-ignore` and `--exclude` are not read there: `exclude` and `unchecked` say it. A declared home
|
|
102
|
+
(`home: <name>`) is still found in every source file.
|
|
103
|
+
- **Packing it.** `pack` (building-fabric-services' `references/package.md`) writes the package's `secrets[]` from the secret slots and `state[]` from the store slots' paths, and refuses a
|
|
104
|
+
package whose members differ (FAC-SEM-160); an empty `state[]` is a copy packed without state, and stays so. A
|
|
105
|
+
hand-written `secrets[]` naming a secret the manifest has no slot for is refused by name, never dropped.
|
|
106
|
+
- **Handing it over** stays the owner's act, each time, on their word for that act (the contract's `source.md`,
|
|
107
|
+
Handing over).
|
|
108
|
+
|
|
72
109
|
## The check
|
|
73
110
|
|
|
74
111
|
`fabric_source_check.py check` reads the files the source would carry (what Git would commit: tracked files and
|