@mmerterden/multi-agent-pipeline 20.17.0 → 20.17.1
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 +12 -0
- package/docs/facts.json +1 -1
- package/docs/features.md +1 -1
- package/install/catalog-history.json +1 -1
- package/manifest.json +18 -18
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/update/SKILL.md +2 -2
- package/pipeline/multi-agent-refs/features/usage-reporting.md +106 -67
- package/pipeline/schemas/prefs.schema.json +23 -2
- package/pipeline/scripts/usage-identity.mjs +312 -53
- package/pipeline/scripts/usage-register.mjs +204 -85
- package/pipeline/scripts/usage-report.mjs +7 -5
- package/pipeline/skills/.skill-manifest.json +3 -3
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -2
package/manifest.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "20.17.
|
|
4
|
-
"commit": "
|
|
5
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"version": "20.17.1",
|
|
4
|
+
"commit": "1f44084eaae7b7269b39de4ffa470ad55b43903a",
|
|
5
|
+
"generatedAt": "2026-10-07T21:19:40.021Z",
|
|
6
6
|
"algorithm": "sha256",
|
|
7
7
|
"fileCount": 1316,
|
|
8
8
|
"files": {
|
|
9
|
-
"CHANGELOG.md": "
|
|
9
|
+
"CHANGELOG.md": "57543e37694daed6e97b42901cc2feb7d415e00841d40e86425cf332ac72c49e",
|
|
10
10
|
"LICENSE": "8d8c51aaf1e1538b180c69965fa038db71be86798cc3e26a143bebfefe16a43e",
|
|
11
11
|
"README.md": "1336cf131fdc0dbab1dd8b90fcd5614bd19d27b92b4f91ab99c3108d61cb51e1",
|
|
12
12
|
"README.tr.md": "7979b32e6c72aedc3a6affe85f33b2840e72f056a836e8546566d259b236ff29",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"docs/best-practices.md": "f8b75b0d38b5896a6a852bb30a1edddeb24dab8b5b7b1d9313290e1241c72024",
|
|
34
34
|
"docs/ecosystem.md": "d504124f421748744599f6974ec71d52664affc47740665651cca5ddc17d0c71",
|
|
35
35
|
"docs/engineering.md": "550528cd47c7d2c921729c68d0782a00ac8e77a4bdfec479f6749f9c3235d188",
|
|
36
|
-
"docs/facts.json": "
|
|
37
|
-
"docs/features.md": "
|
|
36
|
+
"docs/facts.json": "67e3e62d1eae9865ede020f765a50580280fd941041524db7a909a23adc25206",
|
|
37
|
+
"docs/features.md": "87ae163280fe05b36ff9f664b1bf9d98b697cc498731d47298751b439fa7a35c",
|
|
38
38
|
"docs/performance.md": "bbf2f3922c25dcba0c1a9e69ef420e3871a729af5b35009a49b48a5d3c5cd151",
|
|
39
39
|
"docs/recovery-guide.md": "59a8f1b66b34cb9ff5507b3d54dac3b9915e184aa044d9c758d18cac818d510e",
|
|
40
40
|
"docs/server-readiness.md": "ea21eee6a08c6fc0f2d1da8058acd5a50c556cea486d3acfe48fc0b23f4581fc",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"install/_plugin-skills.mjs": "2de429260472a7b60bfe800eabc111624fa5f82a175e283481b05e5349dad572",
|
|
52
52
|
"install/_telemetry.mjs": "5433d753f909beed2c8789272bba05e245482c472f83d3444f58000c4c9a634b",
|
|
53
53
|
"install/_unattended-profile.mjs": "e1ed82bde35d19105ee12c2a551eb778912b0e5c93ab227fd15c993098d98de0",
|
|
54
|
-
"install/catalog-history.json": "
|
|
54
|
+
"install/catalog-history.json": "837e451fe78c2bcc1198125d1fdc40e89f1c51833d24765b998a58095cf235f8",
|
|
55
55
|
"install/claude.mjs": "5a924a9cc51c9e67e26f4bbe9495d8f8226ca6d5065d2b5c9c9f0482fe4064dd",
|
|
56
56
|
"install/codex.mjs": "88c3f90b29fff8579d972d97c90e40f969c8f5dc2d64a6fdc1dfa90155c5e45b",
|
|
57
57
|
"install/copilot.mjs": "300a74f17084d1a38f16428ca7477394c29e33cd755156e19b92e457999be234",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"install/templates/multi-agent-autopilot-awake.plist.template": "ddd25c76c56fcbb38a89de8e35637372d70ace993d6bc487a88ca9cfb702fe1f",
|
|
63
63
|
"install/templates/multi-agent-autopilot.plist.template": "122c8a61cd927edd99375d6e3da40f1d42bcceed5b6641785c8b28bb930bc77e",
|
|
64
64
|
"install/unattended-profile-legacy.json": "f52e86b998956f09ad306b1735a6c10b58580d7082d8a55665a4c6bb15c3aa1f",
|
|
65
|
-
"package.json": "
|
|
65
|
+
"package.json": "bb79203813adec7bca1c031daecc49a813ea3930179b795abe55a20ad387cab4",
|
|
66
66
|
"pipeline/agents/android-architect.md": "11fb74543cb0ebcf9525ca6654fe95d53da7229e0bf4a1149b31fd9005abc453",
|
|
67
67
|
"pipeline/agents/backend-architect.md": "b02a606c301e4714131aed70ae6d16eeb77fbc819a001e2752cff2488d4246de",
|
|
68
68
|
"pipeline/agents/bulk-reader.md": "6597052cd7d205bac2b1c7633f5232fe1a40730664a913b8eb77efd5a786dc25",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"pipeline/commands/multi-agent/search/SKILL.md": "231f0dd266907423cc45feeadc4170852dc6fd45239e0bee3ee4e08d4d0f5958",
|
|
129
129
|
"pipeline/commands/multi-agent/security-review/SKILL.md": "dfc2fad484c81169912062391f7ad97500ef113d95741902e5e18e7dd60b6da1",
|
|
130
130
|
"pipeline/commands/multi-agent/serve/SKILL.md": "e931219d8be258a155a692d23c2b275c2e7e0a761b3f0354c943e26d2ce7b035",
|
|
131
|
-
"pipeline/commands/multi-agent/setup/SKILL.md": "
|
|
131
|
+
"pipeline/commands/multi-agent/setup/SKILL.md": "b6b4af9eac2ec9454dda08d960ab9ed559421e167f6726915b451e86fbb3f058",
|
|
132
132
|
"pipeline/commands/multi-agent/stack/SKILL.md": "6d64e96b9a2d41d25ff077afa84300172cac9bf9dd78ec1d9fbbaf45df34f5dd",
|
|
133
133
|
"pipeline/commands/multi-agent/status/SKILL.md": "b08338841a5282f8ae2494751001aa31cbf4829146a58ed2c395b1c062b48443",
|
|
134
134
|
"pipeline/commands/multi-agent/steer/SKILL.md": "07e738c228ba328f717f86e97e7af207df090b16433e28e613d430c3ff0aee3e",
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
"pipeline/commands/multi-agent/test/SKILL.md": "5a67be2b1ec0321e79f8b7f35be53676e349e55a4f8ca09a07f0de89dadac8c4",
|
|
142
142
|
"pipeline/commands/multi-agent/testflight-validation/SKILL.md": "38fa8d3d3c8340d025e100c53a70183cbad22665b7ddccbb6102c05986cce489",
|
|
143
143
|
"pipeline/commands/multi-agent/uninstall/SKILL.md": "b2124820a6e10cdd72be71df2183aad4f8bd8988ec90248c88599c1514f7d9ab",
|
|
144
|
-
"pipeline/commands/multi-agent/update/SKILL.md": "
|
|
144
|
+
"pipeline/commands/multi-agent/update/SKILL.md": "b87d2b9b284860eb14f5973f640b09de2993493cc1e3676bf14bb877927966ed",
|
|
145
145
|
"pipeline/commands/sim-test.md": "b09038b9511108c77fae5e0c11f8515b5c64eb8b63a77fe8c2ff5907ddd0313a",
|
|
146
146
|
"pipeline/contract/CHANGELOG.md": "0813f5737219bafad3eb4daf809b9754937fae8533e07caf3850e30b2685662b",
|
|
147
147
|
"pipeline/contract/README.md": "6239eb0877d70e70d63db74bae3499599b0425c80c71eceb6bb0a981523eaa89",
|
|
@@ -318,7 +318,7 @@
|
|
|
318
318
|
"pipeline/multi-agent-refs/features/unattended-gates.md": "46b516cac81a4eacf5d58bc3b1613e2266c26f1559be8dac060d1dc6b7d7ca01",
|
|
319
319
|
"pipeline/multi-agent-refs/features/unattended-security.md": "18da3d51c175a42ab6312051a50b9d0339524dad2cc34e0350de62fbf0cece91",
|
|
320
320
|
"pipeline/multi-agent-refs/features/url-enrichment.md": "72e01a799d9fa54b56c762ba404a9f9236adbbf98320e395a96f6b0f5917e76b",
|
|
321
|
-
"pipeline/multi-agent-refs/features/usage-reporting.md": "
|
|
321
|
+
"pipeline/multi-agent-refs/features/usage-reporting.md": "bd8643e804a70d86679e431368e2fff7a8fbe7b121837340e745b1dd221a428d",
|
|
322
322
|
"pipeline/multi-agent-refs/features/valven.md": "13b1fb8a3815330f6f970181506ac117e0d1c42761e5a83454edbd0b383ee1a7",
|
|
323
323
|
"pipeline/multi-agent-refs/features/verify-by-test.md": "b0735adaa7ead797167b8d9ea48a10851a138083c6e638738cc96c66b02a1e37",
|
|
324
324
|
"pipeline/multi-agent-refs/features/verify.md": "1a6db5e7239eac01e51100353013abd16bf785a7fce88b40139fca27f4166be4",
|
|
@@ -450,7 +450,7 @@
|
|
|
450
450
|
"pipeline/schemas/plan-todos.schema.json": "f1dcf8df338b29bbc1d874addd3408c0841a5f869c0b6075efd9242e3e8552d6",
|
|
451
451
|
"pipeline/schemas/planning-output.schema.json": "bc6eda32ecd435cf84d846078f9d38347f8f741f8a427cff15913dd6c380d4b8",
|
|
452
452
|
"pipeline/schemas/pr-request.schema.json": "ae75c4856349d62834802b1189af516bb6fb3d36646831b7ff2fa61d938afcd0",
|
|
453
|
-
"pipeline/schemas/prefs.schema.json": "
|
|
453
|
+
"pipeline/schemas/prefs.schema.json": "d603707539234845e4390cb33e4bfe9a116d7c6485dfcd3207caf786db36ccdc",
|
|
454
454
|
"pipeline/schemas/repo-profile.schema.json": "1a74ef8330da9a26a5a70955f6f9cbb20eda54a8615efaf86c7993d420a7f04e",
|
|
455
455
|
"pipeline/schemas/repos.schema.json": "a9bf56f25c66201c170912e3389bd73e4a3f61922410f83e31a6c6ba47aee861",
|
|
456
456
|
"pipeline/schemas/research-output.schema.json": "54e3ba1b04fdc20fbaa84333b943a8ab95d1395c7b0e0aedc67929184cb49523",
|
|
@@ -663,9 +663,9 @@
|
|
|
663
663
|
"pipeline/scripts/uninstall.mjs": "6ca82cb55910d085feca776a6cd4c28adcf0a42fb07358e4bab27c89a9d913a5",
|
|
664
664
|
"pipeline/scripts/update-check.sh": "9c00647e7ca4249414b2e5af08f61705ab5bd2106b6f66ae8ebce8aa143dc957",
|
|
665
665
|
"pipeline/scripts/update-issue-progress.sh": "ccfef87743e91272e009e396ac07461d2784b2fa84a06c802a582526eeeb9ed9",
|
|
666
|
-
"pipeline/scripts/usage-identity.mjs": "
|
|
667
|
-
"pipeline/scripts/usage-register.mjs": "
|
|
668
|
-
"pipeline/scripts/usage-report.mjs": "
|
|
666
|
+
"pipeline/scripts/usage-identity.mjs": "1ea8ffb5a52aa5f98a7ea491f12af02d86f711666ac0cc37cac59c70e182aaf4",
|
|
667
|
+
"pipeline/scripts/usage-register.mjs": "358bdd13bc9b986618dec5394911beac20d4e07c6c4758e5804ad4b188860ea8",
|
|
668
|
+
"pipeline/scripts/usage-report.mjs": "bc330b3a5657aa99f4ec19dbf9fcca0590d02166f242b40a51b55ac3c0cc1b83",
|
|
669
669
|
"pipeline/scripts/validate-analysis-doc.mjs": "3300212d6d7387f4f2f63e2712dad7dacc53d8c133d575a286d3d4bf06bca431",
|
|
670
670
|
"pipeline/scripts/validate-analysis.mjs": "d2dc9ccf45f6ca2702908761939edd830d18b3b273016a4b449f26fe285d5ea1",
|
|
671
671
|
"pipeline/scripts/validate-code-graph.mjs": "0ceac2f5b59f641334d54dc30bee5265361fb5fe1fc97e2f9791b546efe79941",
|
|
@@ -688,7 +688,7 @@
|
|
|
688
688
|
"pipeline/scripts/worktrees.mjs": "90dfd09b70fffe9b56c331a4ae2692cc248f4898f4ee6aee4239ef0b20888a90",
|
|
689
689
|
"pipeline/scripts/write-state.mjs": "e1198bf970eace07d3eff22b394808a526e473df65d3d58aa2d5a12cfdac8b49",
|
|
690
690
|
"pipeline/scripts/write-store-config.mjs": "b994a061f6febb2ca3d396074d8b51d2c1c1f991d3072d321703380da3639a56",
|
|
691
|
-
"pipeline/skills/.skill-manifest.json": "
|
|
691
|
+
"pipeline/skills/.skill-manifest.json": "443e434af0582dfe6173f3a8148fb13d11f70f909e22119b1acac15049e1b62f",
|
|
692
692
|
"pipeline/skills/.skills-index.json": "2e3876489f0939473e43df854b97fb93ca5c2de5be7ccc69c1997daba26f2e58",
|
|
693
693
|
"pipeline/skills/shared/README.md": "259f1188a867dafbf17ca3796b9b2b13bad8a01b7f6ab45e96eacf0c409c0eab",
|
|
694
694
|
"pipeline/skills/shared/core/apple-archive-compliance/SKILL.md": "7239fef717ea45b79276bfcc2c3903acd57950b6e00dd6a2a66399c4b09cbd51",
|
|
@@ -745,7 +745,7 @@
|
|
|
745
745
|
"pipeline/skills/shared/core/multi-agent-search/SKILL.md": "5f5177cd28cbb13583441fb98402cfa251c78e69de693540584e9a1dcc7692cb",
|
|
746
746
|
"pipeline/skills/shared/core/multi-agent-security-review/SKILL.md": "3c483d5942f2c2b81c0537d4db0b36804c13cabd66fd7fae2972d07a8f239f69",
|
|
747
747
|
"pipeline/skills/shared/core/multi-agent-serve/SKILL.md": "90e4dd7225e10e670118ed05d0c8a9e346112c4bbbdb24a7fe7c5c334a83e848",
|
|
748
|
-
"pipeline/skills/shared/core/multi-agent-setup/SKILL.md": "
|
|
748
|
+
"pipeline/skills/shared/core/multi-agent-setup/SKILL.md": "427df811e5130da1ab6e23ff78202eb9134fb76bcd601924fba5668cbd630158",
|
|
749
749
|
"pipeline/skills/shared/core/multi-agent-stack/SKILL.md": "ac964cd00dd6ed06512530489d867efbc51d7d7614265f9aa022679325d5defe",
|
|
750
750
|
"pipeline/skills/shared/core/multi-agent-status/SKILL.md": "444c3773b52e6786e40bc67c8833ea6aecadbcd4459b01127b4aff152157040a",
|
|
751
751
|
"pipeline/skills/shared/core/multi-agent-steer/SKILL.md": "20f332bd2fe2745da5341f8d8187211fc47c06b4b5f5031e217affee0282ddb5",
|
|
@@ -758,7 +758,7 @@
|
|
|
758
758
|
"pipeline/skills/shared/core/multi-agent-test/SKILL.md": "538c7e27f1137975127883b249ebd552d07a114fe27aa33b31a0e659c93cd742",
|
|
759
759
|
"pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md": "6bfd1569117bfbacb485d831c0b7f262ebb3a2f9471f6177a646f5ce32c06a25",
|
|
760
760
|
"pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md": "9dccf78ffc2fb014d83f67d683d395f56f4fad8b5a36b9aa84e6cbd075b58818",
|
|
761
|
-
"pipeline/skills/shared/core/multi-agent-update/SKILL.md": "
|
|
761
|
+
"pipeline/skills/shared/core/multi-agent-update/SKILL.md": "013317432263490a01d081b657928b977012afb78f75a64d278d94d2daa8e894",
|
|
762
762
|
"pipeline/skills/shared/core/multi-agent/SKILL.md": "3dd44ccc00e41c09e59ad223900a391f80158bd3f69e45d67c684285bc42418d",
|
|
763
763
|
"pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md": "24df1d1dfb47b06b8fafb98938cf1b353fb0245c3a8f8212e197321d537dadff",
|
|
764
764
|
"pipeline/skills/shared/external/NOTICE-dimillian-skills.md": "b98a170d97836f00ac6ee9c80e0befde324a6062071dc06a7eedce65fa5141cd",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "20.17.
|
|
3
|
+
"version": "20.17.1",
|
|
4
4
|
"description": "6-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -153,8 +153,8 @@ Then, **whether they pasted or skipped**, run:
|
|
|
153
153
|
node "$HOME/.claude/scripts/usage-register.mjs" --json
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
If its JSON line says `"needsPersonalAccount":true`, offer
|
|
157
|
-
|
|
156
|
+
If its JSON line says `"needsPersonalAccount":true`, offer once: `gh auth login`,
|
|
157
|
+
or an SSH key on the personal account (the "Personal account" step in
|
|
158
158
|
`$HOME/.claude/multi-agent-refs/features/usage-reporting.md`).
|
|
159
159
|
|
|
160
160
|
It maps whatever token exists and switches reporting on, and requests a
|
|
@@ -135,8 +135,8 @@ and every later block that needs them starts by sourcing it.
|
|
|
135
135
|
reporting off with one status line - never an error. Contract and the data it
|
|
136
136
|
sends: `$HOME/.claude/multi-agent-refs/features/usage-reporting.md`.
|
|
137
137
|
|
|
138
|
-
If its JSON line says `"needsPersonalAccount":true`, offer
|
|
139
|
-
|
|
138
|
+
If its JSON line says `"needsPersonalAccount":true`, offer once: `gh auth login`,
|
|
139
|
+
or an SSH key on the personal account (the "Personal account" step in
|
|
140
140
|
`$HOME/.claude/multi-agent-refs/features/usage-reporting.md`).
|
|
141
141
|
|
|
142
142
|
6. **Show the new version and its changes** (from the packaged CHANGELOG - there is no git history on this channel):
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<!-- /toc -->
|
|
14
14
|
|
|
15
15
|
Reporting needs three things: `usageLog.enabled` true, a token that resolves,
|
|
16
|
-
and a
|
|
16
|
+
and a GitHub account on this machine that can read the pipeline repository. The token
|
|
17
17
|
is arranged by one call (`$HOME/.claude/scripts/usage-register.mjs`) made from
|
|
18
18
|
the three places a machine can first become real: **setup**, **update**, and
|
|
19
19
|
**the Phase 0 exit gate** of a run on a machine that reached neither. Asserted by
|
|
@@ -24,7 +24,8 @@ the three places a machine can first become real: **setup**, **update**, and
|
|
|
24
24
|
`usage-report.mjs` emits coarse run metadata, one record per run, upserted by
|
|
25
25
|
run id. Never prompts, never code, never diffs, never token values, never
|
|
26
26
|
absolute paths, never the repository name (a digest stands in for it). The
|
|
27
|
-
registration call sends
|
|
27
|
+
registration call sends the reporting login and the short hostname, plus the
|
|
28
|
+
signed challenge when the account was found by an SSH key (section 4).
|
|
28
29
|
|
|
29
30
|
Each record carries:
|
|
30
31
|
|
|
@@ -80,96 +81,133 @@ is waiting on a person and is never shown as abandoned. The threshold is
|
|
|
80
81
|
|
|
81
82
|
## 3. The reporting identity
|
|
82
83
|
|
|
83
|
-
The login is the GitHub login of the
|
|
84
|
-
repository** (`usageLog.accessRepo`, default `mmerterden/multi-agent-pipeline`):
|
|
84
|
+
The login is the GitHub login of **the account on this machine that can read the
|
|
85
|
+
pipeline repository** (`usageLog.accessRepo`, default `mmerterden/multi-agent-pipeline`):
|
|
85
86
|
access to that repository is what grants use of the pipeline, so it also decides
|
|
86
|
-
whose name a run carries. `usage-identity.mjs`
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
whose name a run carries. `usage-identity.mjs` finds it with no question asked,
|
|
88
|
+
stopping at the first account that can read the repository:
|
|
89
|
+
|
|
90
|
+
| Order | Method (`usageLog.loginMethod`) | Candidates | Access check |
|
|
91
|
+
|-------|------|------------|--------------|
|
|
92
|
+
| 1 | `gh` | every github.com account `gh auth status` lists: `usageLog.reportAs` (when logged in), the active account, then the rest | `gh api repos/<accessRepo>` with that account's token in the child's environment as `GH_TOKEN` |
|
|
93
|
+
| 2 | `credential` | the token git's credential helper holds for https://github.com: `git credential fill` with `protocol=https`, `host=github.com` on stdin, `GIT_TERMINAL_PROMPT=0`, `GCM_INTERACTIVE=never`, askpass disabled, a timeout | `GET /user` names the login, `GET /repos/<accessRepo>` proves access; through `gh api` with `GH_TOKEN`, or straight to the GitHub API from a child process when gh is not installed |
|
|
94
|
+
| 3 | `ssh` | the private keys `ssh -G github.com` lists (`identityfile`, `~` expanded) and `~/.ssh/id_ed25519`, `id_ecdsa`, `id_rsa`, each only when its `.pub` exists; a `.pub` listed on its own stands for a key held by an agent | `ssh -T git@github.com` names the login (`Hi <login>!`; a deploy key's `owner/repo` is skipped), `git ls-remote git@github.com:<accessRepo>.git HEAD` proves access. Both with `-i <key> -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new` |
|
|
95
|
+
|
|
96
|
+
No token is ever put on an argv, logged or stored: gh and git print it on their
|
|
97
|
+
own stdout, and it travels on only in a child's environment. Batch mode means a
|
|
98
|
+
key that needs a passphrase and is not in ssh-agent is skipped, never prompted
|
|
99
|
+
for. A missing gh, git or ssh binary, a timeout or a failed check only means
|
|
100
|
+
"no candidate"; nothing here fails a caller.
|
|
91
101
|
|
|
92
102
|
Never `identity.name`, which carries a person's real name and sometimes a
|
|
93
103
|
corporate title, and never simply the active `gh` account, which on a machine
|
|
94
104
|
with a work account and a personal account is often the one without access.
|
|
95
105
|
|
|
96
|
-
The answer is cached in prefs (`usageLog.login`, `
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
The answer is cached in prefs (`usageLog.login`, `loginMethod`, `loginKey` for
|
|
107
|
+
the SSH key path, `loginRepo`, `loginCheckedAt`, `loginReason`) for 7 days, or
|
|
108
|
+
1 day when no account was found, so a phase boundary costs no network call. A
|
|
109
|
+
cached SSH login whose key file is gone is re-checked. Refresh it after changing
|
|
110
|
+
accounts or keys, or being granted access:
|
|
99
111
|
|
|
100
112
|
```bash
|
|
101
113
|
node "$HOME/.claude/scripts/usage-identity.mjs" --refresh
|
|
102
114
|
```
|
|
103
115
|
|
|
104
|
-
**No account with access
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
**No gh account at all, no report.** The emitter sends nothing and writes one
|
|
113
|
-
line to stderr (`usage-report: not sent - no GitHub account is logged in ...`);
|
|
114
|
-
registration is skipped with the same reason.
|
|
116
|
+
**No account with access, no report.** Nothing is reported under an account
|
|
117
|
+
that cannot read the repository: the server accepts only the repository owner
|
|
118
|
+
and its collaborators. The emitter sends nothing and writes one line to stderr
|
|
119
|
+
(`usage-report: not sent - no GitHub account on this machine can read ...`,
|
|
120
|
+
naming what was tried); registration is skipped with the same reason. A cache
|
|
121
|
+
entry or registration written by 20.17.0 with `loginFallback` /
|
|
122
|
+
`registeredFallback` set is treated as no account: it is re-checked at once and
|
|
123
|
+
replaced as soon as an account with access is found.
|
|
115
124
|
|
|
116
125
|
**`--quiet` still speaks once.** The Phase 0 backstop discards stdout, so a
|
|
117
126
|
registration that leaves reporting off for a reason the user can fix (a refused
|
|
118
|
-
login, no
|
|
119
|
-
`multi-agent: usage reporting is off - <reason>`, on
|
|
127
|
+
login, no account with access, a key that cannot sign, an unreachable endpoint)
|
|
128
|
+
prints one stderr line, `multi-agent: usage reporting is off - <reason>`, on
|
|
129
|
+
every run until it is fixed.
|
|
120
130
|
|
|
121
131
|
### Personal account
|
|
122
132
|
|
|
123
133
|
A registration is pinned: the server binds the token to the login it verified,
|
|
124
134
|
and the machine keeps that login in `usageLog.registeredAs`. Every later record
|
|
125
|
-
is named after it, with no
|
|
126
|
-
(`decideRegistration`). So the personal account has to be
|
|
127
|
-
once, at the moment of registration
|
|
128
|
-
|
|
129
|
-
`usage-register.mjs --json` reports `needsPersonalAccount: true`
|
|
130
|
-
machine is not pinned
|
|
131
|
-
|
|
132
|
-
once (AskUserQuestion per
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
is named after it, with no identity check, and finding no account later does not
|
|
136
|
+
undo it (`decideRegistration`). So the personal account has to be reachable only
|
|
137
|
+
once, at the moment of registration.
|
|
138
|
+
|
|
139
|
+
`usage-register.mjs --json` reports `needsPersonalAccount: true` only when the
|
|
140
|
+
machine is not pinned and no account was found at all: no gh account, no
|
|
141
|
+
credential-helper token and no SSH key with access. That is the last resort.
|
|
142
|
+
Setup and update then ask once (AskUserQuestion per
|
|
143
|
+
`$HOME/.claude/multi-agent-refs/picker-contract.md`; label
|
|
144
|
+
`Add personal account (Recommended)` / `Skip`) and offer either fix:
|
|
145
|
+
|
|
146
|
+
- **gh**: note the active account (`gh api user --jq .login`), have the person
|
|
147
|
+
run the browser login for the account that holds access in their own terminal
|
|
148
|
+
(in Claude Code: `! gh auth login --hostname github.com --web`; gh keeps both
|
|
149
|
+
accounts), then switch the work account back so pull requests keep their
|
|
150
|
+
author: `gh auth switch --hostname github.com --user <the noted account>`.
|
|
151
|
+
- **SSH key**: add this machine's public key (for example `~/.ssh/id_ed25519.pub`)
|
|
152
|
+
under the personal account's GitHub Settings > SSH and GPG keys. Nothing else
|
|
153
|
+
changes on the machine.
|
|
154
|
+
|
|
155
|
+
Then `node "$HOME/.claude/scripts/usage-register.mjs" --refresh --json` finds
|
|
156
|
+
the account and pins it. Skip leaves reporting off; the next update asks again.
|
|
146
157
|
|
|
147
158
|
## 4. The server side
|
|
148
159
|
|
|
149
160
|
`/api/usage/register` requires proof that the caller owns the login it names.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
`Authorization: Bearer <token>`.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
The proof depends on how the account was found:
|
|
162
|
+
|
|
163
|
+
- **gh**: `gh auth token --user <login>` (gh prints it on its own stdout), sent
|
|
164
|
+
as `Authorization: Bearer <token>`.
|
|
165
|
+
- **credential**: the credential helper's token, fetched again at registration
|
|
166
|
+
(never kept from the identity check), sent the same way.
|
|
167
|
+
- **ssh**: no token at all. (a) `POST <register url>/challenge` with
|
|
168
|
+
`{ "u": <login> }` returns `{ challenge, namespace, expiresAt }`. (b) The exact
|
|
169
|
+
challenge bytes (UTF-8, no trailing newline) are written to a `0600` file in a
|
|
170
|
+
fresh temp dir and signed with `ssh-keygen -Y sign -f <key> -n <namespace>`,
|
|
171
|
+
stdin closed and askpass disabled, so a key that needs a passphrase fails at
|
|
172
|
+
once; then with `-f <key>.pub`, which signs through ssh-agent when the key is
|
|
173
|
+
loaded there. The temp dir is removed afterwards. (c) `POST <register url>`
|
|
174
|
+
with `{ "u", "c", "ssh": { "challenge", "signature" } }` and no
|
|
175
|
+
Authorization header.
|
|
176
|
+
|
|
177
|
+
For a bearer, the server resolves the token to a GitHub login and refuses a
|
|
178
|
+
mismatch. For an SSH proof, the challenge is stateless and HMAC-bound to the
|
|
179
|
+
login, valid for five minutes; the server checks it, then accepts the signature
|
|
180
|
+
only from one of the login's public keys on GitHub
|
|
181
|
+
(`https://github.com/<login>.keys`; ed25519, rsa-sha2-256/512, ecdsa nistp256). Either way it then checks that login with a
|
|
182
|
+
server-side token (the repository owner, or a collaborator of the repository)
|
|
183
|
+
before it issues a token, and pins the login to that token. The body's `u` is a
|
|
184
|
+
hint for a bearer and the claim being proven for a signature.
|
|
157
185
|
|
|
158
186
|
The proof is sent only over https to the default reporting host or a host listed
|
|
159
187
|
in `usageLog.trustedHosts`, or plain http to loopback (`127.0.0.1`, `localhost`,
|
|
160
|
-
`[::1]`) for local development; any other endpoint is refused before
|
|
161
|
-
|
|
162
|
-
token nor the ingest token can be carried to
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
188
|
+
`[::1]`) for local development; any other endpoint is refused before any token
|
|
189
|
+
is read or any key is used. Redirects are not followed by any of the calls, so
|
|
190
|
+
neither a GitHub token, a signature nor the ingest token can be carried to
|
|
191
|
+
another host.
|
|
192
|
+
|
|
193
|
+
| Answer | Status line |
|
|
194
|
+
|--------|-------------|
|
|
195
|
+
| `401` / `403` `login_mismatch` | the login that could not be confirmed (for gh: `gh auth status` must list it) |
|
|
196
|
+
| `401` `ssh_signature_invalid` | the signature did not verify |
|
|
197
|
+
| `401` `ssh_key_not_on_account` | the key is not on that account; add its `.pub` to it |
|
|
198
|
+
| `401` `ssh_key_unsupported` | the key type is not accepted; use an ed25519, rsa or ecdsa-p256 key |
|
|
199
|
+
| `403` (no access) | the login needs collaborator access |
|
|
200
|
+
| challenge `404` / `405` | the endpoint does not accept an SSH key as proof yet |
|
|
201
|
+
| signing failed | the key needs a passphrase and is not in ssh-agent: `ssh-add <key>` |
|
|
202
|
+
| `accepted: false` | `declined` |
|
|
203
|
+
|
|
204
|
+
gh or the credential helper having no token for the login sends nothing.
|
|
205
|
+
`/api/usage/ingest` reports every record under the pinned login and ignores the
|
|
206
|
+
name the client sent; a pinned login that is no longer the owner or a
|
|
207
|
+
collaborator is dropped. Records from any other account are hidden from the
|
|
208
|
+
panel. `usage-register.mjs` replaces a stored token whose `registeredAs` differs
|
|
209
|
+
from the verified login, that predates verification, or that a 20.17.0 fallback
|
|
210
|
+
registration left, because a token reports under the login it was issued for.
|
|
173
211
|
|
|
174
212
|
## 5. The token
|
|
175
213
|
|
|
@@ -189,7 +227,8 @@ switch) holds the prefs file's lock and replaces the file atomically at mode
|
|
|
189
227
|
|
|
190
228
|
`usageLog.optOut: true` blocks registration permanently and is checked before
|
|
191
229
|
anything else - before the identity check, the network call and any credential
|
|
192
|
-
read (the credential store
|
|
230
|
+
read (the credential store, `gh auth token`, `git credential fill` and any SSH
|
|
231
|
+
key).
|
|
193
232
|
|
|
194
233
|
The other silence is not a choice: offline, endpoint down, ingest disabled by the
|
|
195
234
|
admin, no account with access, or a credential store that refuses the write. That
|
|
@@ -1272,11 +1272,24 @@
|
|
|
1272
1272
|
"type": "string",
|
|
1273
1273
|
"pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$",
|
|
1274
1274
|
"default": "mmerterden/multi-agent-pipeline",
|
|
1275
|
-
"description": "owner/repo whose read access decides the reporting identity (usage-identity.mjs). Reporting uses the first
|
|
1275
|
+
"description": "owner/repo whose read access decides the reporting identity (usage-identity.mjs). Reporting uses the first account on the machine that can read it (gh accounts, then the git credential helper, then SSH keys), and sends nothing when none can."
|
|
1276
1276
|
},
|
|
1277
1277
|
"login": {
|
|
1278
1278
|
"type": ["string", "null"],
|
|
1279
|
-
"description": "Cached result of the identity check: the
|
|
1279
|
+
"description": "Cached result of the identity check: the GitHub account on this machine that can read accessRepo, or null when none could. Written by usage-identity.mjs; refresh with `node ~/.claude/scripts/usage-identity.mjs --refresh`."
|
|
1280
|
+
},
|
|
1281
|
+
"loginMethod": {
|
|
1282
|
+
"type": ["string", "null"],
|
|
1283
|
+
"enum": ["gh", "credential", "ssh", null],
|
|
1284
|
+
"description": "How the cached login was found: a gh account, the git credential helper's github.com token, or an SSH key. Registration proves the login the same way. Absent on a cache written before 20.17.1, which means gh."
|
|
1285
|
+
},
|
|
1286
|
+
"loginKey": {
|
|
1287
|
+
"type": ["string", "null"],
|
|
1288
|
+
"description": "Path of the SSH private key the login was found with (loginMethod ssh only). A missing key file invalidates the cache."
|
|
1289
|
+
},
|
|
1290
|
+
"loginFallback": {
|
|
1291
|
+
"type": "boolean",
|
|
1292
|
+
"description": "Deprecated (20.17.0). Marked a cached login that could not read accessRepo; such a cache entry is re-checked at once and the key is removed."
|
|
1280
1293
|
},
|
|
1281
1294
|
"loginRepo": {
|
|
1282
1295
|
"type": "string",
|
|
@@ -1294,6 +1307,14 @@
|
|
|
1294
1307
|
"type": "string",
|
|
1295
1308
|
"description": "The login the stored ingest token was issued for. usage-register.mjs replaces the token when the verified login differs, because the server pins each token to one login."
|
|
1296
1309
|
},
|
|
1310
|
+
"registeredAt": {
|
|
1311
|
+
"type": "string",
|
|
1312
|
+
"description": "ISO time of the registration that issued the stored token."
|
|
1313
|
+
},
|
|
1314
|
+
"registeredFallback": {
|
|
1315
|
+
"type": "boolean",
|
|
1316
|
+
"description": "Deprecated (20.17.0). true marked a registration made with an account that cannot read accessRepo; it is not treated as pinned and is replaced once an account with access is found."
|
|
1317
|
+
},
|
|
1297
1318
|
"includeTitle": {
|
|
1298
1319
|
"type": "boolean",
|
|
1299
1320
|
"default": false,
|