@delorenj/pjangler 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +528 -0
  2. package/contracts/fleet-contract.yaml +513 -0
  3. package/dist/index.js +9333 -1509
  4. package/dist/mcp-server.js +6634 -1096
  5. package/dist/prompt.js +2 -1
  6. package/package.json +10 -4
  7. package/templates/hermes-agent/copier.yml +16 -3
  8. package/templates/hermes-agent/template/.runtime-scaffold/memories/MEMORY.md +7 -4
  9. package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +88 -94
  10. package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +44 -21
  11. package/templates/hermes-agent/template/.scripts/30-telegram.sh +182 -171
  12. package/templates/hermes-agent/template/.scripts/31-slack.sh +260 -165
  13. package/templates/hermes-agent/template/.scripts/40-plane.sh +45 -36
  14. package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +210 -41
  15. package/templates/hermes-agent/template/.scripts/70-systemd.sh +129 -15
  16. package/templates/hermes-agent/template/.scripts/80-registry.sh +42 -6
  17. package/templates/hermes-agent/template/.scripts/99-summary.sh +69 -16
  18. package/templates/hermes-agent/template/.scripts/_lib.sh +773 -0
  19. package/templates/hermes-agent/template/.scripts/channel-transaction.py +2340 -0
  20. package/templates/hermes-agent/template/.scripts/config.example.toml +8 -2
  21. package/templates/hermes-agent/template/.scripts/credential-launch.sh +5 -1
  22. package/templates/hermes-agent/template/.scripts/heartbeat.sh +2 -3
  23. package/templates/hermes-agent/template/.scripts/lib/profile-config-lock.py +182 -0
  24. package/templates/hermes-agent/template/.scripts/lib/profile-config-seed.py +108 -0
  25. package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +93 -4
  26. package/templates/hermes-agent/template/.scripts/lib/voice-config.py +546 -0
  27. package/templates/hermes-agent/template/.scripts/providers/linear.sh +138 -25
  28. package/templates/hermes-agent/template/.scripts/providers/plane.sh +408 -51
  29. package/templates/hermes-agent/template/.scripts/providers/trello.sh +54 -6
  30. package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-autonomous-review.sh +257 -43
  31. package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-close-gate.sh +142 -25
  32. package/templates/hermes-agent/template/.scripts/sentinel/docs/autonomous-delegated-review.md +13 -19
  33. package/templates/hermes-agent/template/.scripts/sentinel/docs/bloodbank-events.md +29 -36
  34. package/templates/hermes-agent/template/.scripts/sentinel/docs/continuous-ticket-orchestration.md +3 -1
  35. package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +7 -8
  36. package/templates/hermes-agent/template/.scripts/store-onepassword-secret.py +260 -0
  37. package/templates/hermes-agent/template/SOUL.md.jinja +14 -16
  38. package/templates/hermes-agent/template/hermes.jinja +1 -1
  39. package/templates/hermes-agent/template/role.yaml.jinja +15 -4
@@ -0,0 +1,513 @@
1
+ # 33GOD fleet authority and managed-state contract.
2
+ #
3
+ # DECLARATION ONLY. This file records versions, authority owners,
4
+ # one-directional projections, lifecycle classes, the canonical service model,
5
+ # the activation gate, and retired modes. It carries no runtime observation, no
6
+ # credential, no host secret, and no absolute host path: stores are named by
7
+ # the environment keys that resolve them and every variable segment of a field
8
+ # path is a {placeholder}.
9
+ #
10
+ # Field paths are dotted key paths that exist in the live stores today. Roots:
11
+ # projects.* PJangler project registry
12
+ # agents.* Hermes agent registry, per-agent rows
13
+ # gateways.* Hermes agent registry, fleet-shared gateway block
14
+ # profiles.* generated Hermes profile tree
15
+ # scaffold.* tracked per-agent role scaffold
16
+ # units.* systemd user units
17
+ # processes.* observed Hermes processes (read-only)
18
+ #
19
+ # Namespaced `x-` keys at any depth round-trip verbatim and are never
20
+ # interpreted as policy.
21
+ #
22
+ # `service_model` and `activation` accept keys beyond the required ones on
23
+ # purpose: an unknown healthy-mode declaration must reach the retired-mode scan
24
+ # rather than be rejected as an unknown key, because rejecting it would hide the
25
+ # very drift this contract exists to name.
26
+
27
+ schema_version: 2
28
+ contract_version: 1.1.0
29
+
30
+ compatibility:
31
+ min_schema_version: 1
32
+ max_schema_version: 2
33
+
34
+ x-delonet/provenance:
35
+ assessment: fleet-convergence-live-assessment-2026-08-31
36
+ epic: registry-wide-fleet-convergence-control-plane
37
+
38
+ authorities:
39
+ project_identity:
40
+ owner: project-registry
41
+ store: pjangler-project-registry
42
+ store_env:
43
+ - PJ_PROJECT_REGISTRY
44
+ notes:
45
+ - Project identity and project-to-board binding.
46
+ - Board provenance fields exist only here, never in the agent registry.
47
+ writable_fields:
48
+ - projects.{slug}.name
49
+ - projects.{slug}.slug
50
+ - projects.{slug}.repo_path
51
+ - projects.{slug}.description
52
+ - projects.{slug}.status
53
+ - projects.{slug}.source_artifacts
54
+ - projects.{slug}.template
55
+ - projects.{slug}.ticket_provider.type
56
+ - projects.{slug}.ticket_provider.workspace
57
+ - projects.{slug}.ticket_provider.identifier
58
+ - projects.{slug}.ticket_provider.identifier_source
59
+ - projects.{slug}.ticket_provider.identifier_fetched_at
60
+ - projects.{slug}.ticket_provider.board_id
61
+ - projects.{slug}.ticket_provider.board_confirmed_at
62
+ - projects.{slug}.ticket_provider.board_url
63
+ - projects.{slug}.ticket_provider.state
64
+ - projects.{slug}.agents.{role}.role
65
+ - projects.{slug}.agents.{role}.provisioning_state
66
+ - projects.{slug}.agents.{role}.role_dir
67
+ - projects.{slug}.automation
68
+ - projects.{slug}.notebook
69
+ - projects.{slug}.created_at
70
+ - projects.{slug}.updated_at
71
+
72
+ agent_operational_records:
73
+ owner: hermes-agent-registry
74
+ store: hermes-agent-registry
75
+ store_env:
76
+ - HERMES_AGENTS_REGISTRY
77
+ - HERMES_FLEET_REGISTRY_FILE
78
+ notes:
79
+ - Operational agent, profile, and routing records.
80
+ - The two store_env keys disagree today. The TypeScript reader honours
81
+ HERMES_AGENTS_REGISTRY, the shell provisioner honours
82
+ HERMES_FLEET_REGISTRY_FILE. Both are recorded so convergence is a
83
+ declared task, not a silent surprise.
84
+ - Bloodbank routing metadata is discovery, not execution authority. The
85
+ single activation flag lives under the bloodbank_activation authority.
86
+ writable_fields:
87
+ - agents.{agent_id}.repo
88
+ - agents.{agent_id}.role
89
+ - agents.{agent_id}.display_name
90
+ - agents.{agent_id}.project_path
91
+ - agents.{agent_id}.role_dir
92
+ - agents.{agent_id}.profile_name
93
+ - agents.{agent_id}.provisioned_at
94
+ - agents.{agent_id}.runtime_repo
95
+ - agents.{agent_id}.telegram.provisioning_status
96
+ - agents.{agent_id}.slack.provisioning_status
97
+ - agents.{agent_id}.bloodbank.gateway_scope
98
+ - agents.{agent_id}.bloodbank.target_agent_id
99
+ - agents.{agent_id}.hermes.bin
100
+ - agents.{agent_id}.hermes.repo
101
+ - agents.{agent_id}.hermes.git_url
102
+ - agents.{agent_id}.hermes.git_ref
103
+ - agents.{agent_id}.hermes.git_sha
104
+ - agents.{agent_id}.hermes.fleet_env
105
+ - gateways.bloodbank.scope
106
+ - gateways.bloodbank.profile_name
107
+ - gateways.bloodbank.command_subject
108
+ - gateways.bloodbank.target_field
109
+ - gateways.bloodbank.systemd_unit
110
+
111
+ board_identity_projection:
112
+ owner: project-registry
113
+ store: hermes-agent-registry
114
+ store_env:
115
+ - HERMES_AGENTS_REGISTRY
116
+ - HERMES_FLEET_REGISTRY_FILE
117
+ notes:
118
+ - The one cross-store write that actually happens today. `pj project
119
+ identity --apply` copies confirmed board identity from the project
120
+ registry into the agent registry.
121
+ - Held as its own block so the agent registry's own writers cannot claim
122
+ these fields, and so the projections that target them have something
123
+ real to point at.
124
+ writable_fields:
125
+ - agents.{agent_id}.plane.workspace
126
+ - agents.{agent_id}.plane.project_id
127
+ - agents.{agent_id}.plane.identifier
128
+
129
+ generated_profile_inputs:
130
+ owner: hermes-profile-renderer
131
+ store: hermes-profile-tree
132
+ store_env:
133
+ - HERMES_FLEET_HOME
134
+ notes:
135
+ - config.yaml is generated by deep-merging the shared base with the
136
+ per-profile config.delta.yaml. It is never hand-edited.
137
+ - The rest of config.delta.yaml is the operator-owned override SSOT. Only
138
+ the three fleet-owned dotted paths listed here are rewritten by the
139
+ renderer.
140
+ writable_fields:
141
+ - profiles.{profile_name}.config.yaml
142
+ - profiles.{profile_name}.config.delta.memory.provider
143
+ - profiles.{profile_name}.config.delta.memory.memory_enabled
144
+ - profiles.{profile_name}.config.delta.memory.user_profile_enabled
145
+
146
+ tracked_role_scaffold:
147
+ owner: hermes-agent-template
148
+ store: hermes-agent-role-scaffold
149
+ store_env:
150
+ - HERMES_TEMPLATE_RUNTIME_SCAFFOLD
151
+ - RUNTIME_SCAFFOLD_DIR
152
+ notes:
153
+ - The committed template at its pinned gitlink owns every tracked asset in
154
+ a per-agent role directory. Role-local runtime bytes are ignored and are
155
+ owned by nobody.
156
+ writable_fields:
157
+ - scaffold.role.yaml
158
+ - scaffold.SOUL.md
159
+ - scaffold.hermes
160
+ - scaffold.momo
161
+ - scaffold.sentinel.prompt.md
162
+ - scaffold.gitignore
163
+ - scaffold.scripts
164
+ - scaffold.runtime-scaffold
165
+
166
+ systemd_lifecycle:
167
+ owner: hermes-fleet-provisioner
168
+ store: systemd-user-manager
169
+ store_env:
170
+ - XDG_CONFIG_HOME
171
+ notes:
172
+ - Unit files and the registry rows that name them are written by the
173
+ provisioner, not by registry editing paths.
174
+ writable_fields:
175
+ - units.hermes-{agent_id}-gateway.service
176
+ - units.hermes-{agent_id}-heartbeat.service
177
+ - units.hermes-{agent_id}-heartbeat.timer
178
+ - units.hermes-fleet-bloodbank-gateway.service
179
+ - agents.{agent_id}.systemd.gateway_unit
180
+ - agents.{agent_id}.systemd.heartbeat_timer
181
+
182
+ live_process_observations:
183
+ owner: fleet-observer
184
+ store: process-table
185
+ store_env: []
186
+ read_only: true
187
+ notes:
188
+ - Observation only. A process is attributed and classified; it is never
189
+ written to, and a drain is a separately authorized effect owned by a
190
+ later story.
191
+ writable_fields: []
192
+
193
+ bloodbank_activation:
194
+ owner: hermes-agent-registry
195
+ store: hermes-agent-registry
196
+ store_env:
197
+ - HERMES_AGENTS_REGISTRY
198
+ - HERMES_FLEET_REGISTRY_FILE
199
+ notes:
200
+ - The single field that can grant execution authority. Held apart from the
201
+ operational records so discovery can never widen into dispatch.
202
+ writable_fields:
203
+ - agents.{agent_id}.bloodbank.enabled
204
+
205
+ projections:
206
+ - field: project_repository_path
207
+ source: projects.{slug}.repo_path
208
+ target: agents.{agent_id}.project_path
209
+ direction: pjangler_project_registry_to_hermes_agent_registry
210
+ writable_by: hermes-agent-registry
211
+
212
+ - field: project_slug
213
+ source: projects.{slug}.slug
214
+ target: agents.{agent_id}.repo
215
+ direction: pjangler_project_registry_to_hermes_agent_registry
216
+ writable_by: hermes-agent-registry
217
+
218
+ - field: board_identifier
219
+ source: projects.{slug}.ticket_provider.identifier
220
+ target: agents.{agent_id}.plane.identifier
221
+ direction: pjangler_project_registry_to_hermes_agent_registry
222
+ writable_by: project-registry
223
+
224
+ - field: board_id
225
+ source: projects.{slug}.ticket_provider.board_id
226
+ target: agents.{agent_id}.plane.project_id
227
+ direction: pjangler_project_registry_to_hermes_agent_registry
228
+ writable_by: project-registry
229
+
230
+ - field: board_workspace
231
+ source: projects.{slug}.ticket_provider.workspace
232
+ target: agents.{agent_id}.plane.workspace
233
+ direction: pjangler_project_registry_to_hermes_agent_registry
234
+ writable_by: project-registry
235
+
236
+ - field: agent_role_directory
237
+ source: agents.{agent_id}.role_dir
238
+ target: projects.{slug}.agents.{role}.role_dir
239
+ direction: hermes_agent_registry_to_pjangler_project_registry
240
+ writable_by: project-registry
241
+
242
+ classifications:
243
+ managed_agent:
244
+ notes:
245
+ - A registered agent row. Instances are registry rows, not contract
246
+ entries, so this class declares its required shape and carries none.
247
+ required_fields:
248
+ - id
249
+ - kind
250
+ - owner
251
+ - source
252
+ - lifecycle_state
253
+ entries: []
254
+
255
+ managed_shared_service:
256
+ notes:
257
+ - Shared or specialist fleet state that is deliberately managed but is not
258
+ a per-agent row.
259
+ required_fields:
260
+ - id
261
+ - kind
262
+ - owner
263
+ - source
264
+ - lifecycle_state
265
+ - rationale
266
+ - policy_domains
267
+ entries:
268
+ - id: fleet-bloodbank-gateway
269
+ kind: shared-service
270
+ owner: hermes-fleet-provisioner
271
+ source: gateways.bloodbank
272
+ lifecycle_state: managed
273
+ rationale: One shared gateway owns Bloodbank command ingress fleet-wide.
274
+ policy_domains:
275
+ - systemd
276
+ - bloodbank
277
+ - profile
278
+ - id: fleet-shared-profile-base
279
+ kind: shared-config
280
+ owner: hermes-profile-renderer
281
+ source: profiles.base.config.yaml
282
+ lifecycle_state: managed
283
+ rationale: Every generated profile config is a merge of this base.
284
+ policy_domains:
285
+ - profile
286
+
287
+ intentionally_unmanaged:
288
+ notes:
289
+ - State an operator has decided the control plane must observe, report,
290
+ and leave alone. Instances are recorded when an observation is
291
+ classified; nothing is declared up front.
292
+ required_fields:
293
+ - id
294
+ - kind
295
+ - owner
296
+ - source
297
+ - lifecycle_state
298
+ - rationale
299
+ - policy_domains
300
+ entries: []
301
+
302
+ retired:
303
+ notes:
304
+ - Drift that used to be a supported mode. The retired block below is the
305
+ authoritative list; entries here are per-instance sightings.
306
+ required_fields:
307
+ - id
308
+ - kind
309
+ - owner
310
+ - source
311
+ - lifecycle_state
312
+ - rationale
313
+ - policy_domains
314
+ entries: []
315
+
316
+ unclassified:
317
+ notes:
318
+ - The default for anything observed that no rule above claims. It is a
319
+ finding for an operator, never a licence to delete.
320
+ required_fields:
321
+ - id
322
+ - kind
323
+ - owner
324
+ - source
325
+ - lifecycle_state
326
+ - rationale
327
+ - policy_domains
328
+ entries: []
329
+
330
+ service_model:
331
+ per_agent:
332
+ gateway_unit: hermes-{agent_id}-gateway.service
333
+ heartbeat_service: hermes-{agent_id}-heartbeat.service
334
+ heartbeat_timer: hermes-{agent_id}-heartbeat.timer
335
+ fleet_shared:
336
+ bloodbank_gateway_unit: hermes-fleet-bloodbank-gateway.service
337
+ bloodbank_gateway_profile: fleet-bloodbank-gateway
338
+ command_subject: bloodbank.cmd.agent.invocation.start
339
+ target_field: data.target_agent_id
340
+ profile_layout:
341
+ root: "{HERMES_FLEET_HOME}/profiles/{profile_name}"
342
+ symlink_allowed: false
343
+ identity_file: profile.yaml
344
+ override_file: config.delta.yaml
345
+ generated_file: config.yaml
346
+ generated_marker: GENERATED FILE -- DO NOT EDIT
347
+
348
+ # Which gaps are AUTHORIZED, and nothing else.
349
+ #
350
+ # Optional, and schema 1 contracts that omit it still load. What it changes is
351
+ # what an aggregate may CLAIM: a skip, a warning, a deferred capability, or a
352
+ # managed exception is "justified" only if it is named here, and anything
353
+ # unjustified keeps the fleet from claiming proof. Nothing in this block grants
354
+ # a capability, relaxes the activation gate, or turns an observation into a
355
+ # pass -- an authorized gap is still reported with its own state.
356
+ health_policy:
357
+ # Domains an aggregate must have observed before it may claim proof. All nine
358
+ # are required; the deferred_capabilities below are what carve out the halves
359
+ # no adapter exists for in this release.
360
+ required_domains:
361
+ - registry
362
+ - project_binding
363
+ - template_scaffold
364
+ - profile
365
+ - runtime
366
+ - systemd
367
+ - live_process
368
+ - bloodbank
369
+ - release_provenance
370
+
371
+ # A capability no observer in this release can answer, and the story that owns
372
+ # it. Each entry authorizes ONE unsupported answer; it never authorizes
373
+ # inferring the answer from something else.
374
+ deferred_capabilities:
375
+ - domain: systemd
376
+ capability: unit_topology
377
+ reason: >-
378
+ No systemd observer exists in this release. The unit names reported for
379
+ an agent are the patterns service_model.per_agent derives, carried as
380
+ expectations and never as observations of the user manager.
381
+ owner_story: "1.8"
382
+ - domain: live_process
383
+ capability: process_attribution
384
+ reason: >-
385
+ No process observer exists in this release: nothing in the build reads
386
+ the process table, so no running Hermes process can be attributed to a
387
+ registry row or classified as sprawl.
388
+ owner_story: "1.9"
389
+ - domain: bloodbank
390
+ capability: routing_liveness
391
+ reason: >-
392
+ The stored routing record is observed; whether the fleet-shared gateway
393
+ can dispatch to it is not. Routing readiness is a separate authority
394
+ from the record and must never be inferred from it.
395
+ owner_story: "1.10"
396
+ - domain: template_scaffold
397
+ capability: scaffold.template_ref
398
+ reason: >-
399
+ A deployed role scaffold records no template ref, so there is no
400
+ recorded value on this host to compare against the pinned gitlink and
401
+ none may be invented.
402
+ owner_story: "1.6"
403
+ - domain: release_provenance
404
+ capability: profile.render_generation
405
+ reason: >-
406
+ A generated profile config carries only the generated-file marker. The
407
+ renderer records no generation identity, so nothing comparable exists
408
+ until generated profile health is proven.
409
+ owner_story: "1.7"
410
+ - domain: release_provenance
411
+ capability: fleet.registry_file
412
+ reason: >-
413
+ The host config names the agent registry through an unexpanded shell
414
+ variable and this control plane must not resolve one. It is the same
415
+ declared divergence the agent_operational_records authority records in
416
+ its two store_env keys.
417
+ owner_story: "1.1"
418
+
419
+ # A rule whose warn is upstream cadence rather than fleet drift.
420
+ allowed_warnings:
421
+ - rule_id: bmad.version
422
+ reason: >-
423
+ A currency check against the published BMAD release, cached for an hour
424
+ and degraded to a skip offline. A newer upstream release is upstream
425
+ cadence, not drift in this fleet.
426
+ owner: bmad-method
427
+
428
+ # A rule or domain whose skip is a deliberate property of a read-only default
429
+ # run rather than an observation nobody got round to.
430
+ allowed_skips:
431
+ - rule_id: notebook.remote-notebook
432
+ reason: >-
433
+ A default audit makes no network request, so remote notebook state is
434
+ not applicable to it.
435
+ - rule_id: notebook.overview-note
436
+ reason: >-
437
+ A default audit makes no network request, so the remote Overview note is
438
+ not applicable to it.
439
+ - rule_id: notebook.skill-installed
440
+ reason: >-
441
+ A default audit reads no global path, so the host skill projection is
442
+ not applicable to it.
443
+ - rule_id: notebook.hooks-projected
444
+ reason: >-
445
+ A default audit reads no global settings file, so the host hook
446
+ projection is not applicable to it.
447
+
448
+ # How long a recorded timestamp may go unrefreshed before the value it stamps
449
+ # stops counting as current evidence. Reported as a BUCKET and never as an
450
+ # age: an age in seconds would make two runs over unchanged state differ.
451
+ freshness:
452
+ - field: projects.{slug}.ticket_provider.board_confirmed_at
453
+ max_age_days: 180
454
+ applies_to: project_binding
455
+ - field: projects.{slug}.ticket_provider.identifier_fetched_at
456
+ max_age_days: 180
457
+ applies_to: project_binding
458
+ - field: agents.{agent_id}.provisioned_at
459
+ max_age_days: 365
460
+ applies_to: registry
461
+
462
+ activation:
463
+ states:
464
+ - discovered
465
+ - installed
466
+ - healthy
467
+ - routing_ready
468
+ - activated
469
+ execution_authority:
470
+ field: agents.{agent_id}.bloodbank.enabled
471
+ owner: hermes-agent-registry
472
+ strict: true
473
+ default: deny
474
+ routing_prerequisites:
475
+ - field: agents.{agent_id}.bloodbank.gateway_scope
476
+ constraint: equals-fleet
477
+ - field: agents.{agent_id}.bloodbank.target_agent_id
478
+ constraint: equals-agent-id
479
+ - field: agents.{agent_id}.profile_name
480
+ constraint: nonblank
481
+
482
+ retired:
483
+ - id: per-agent-bloodbank-consumer
484
+ reason: A per-agent consumer races the shared gateway and duplicates work.
485
+ superseded_by: service_model.fleet_shared.bloodbank_gateway_unit
486
+ detect:
487
+ - '-consumer\.service'
488
+ - 'consumer_unit'
489
+ - id: per-agent-checkpoint-timer
490
+ reason: Checkpoint-only ticks proved liveness without proving health.
491
+ superseded_by: service_model.per_agent.heartbeat_timer
492
+ detect:
493
+ - '-checkpoint\.timer'
494
+ - 'checkpoint_timer'
495
+ - id: n8n-owned-truth
496
+ reason: Orchestration may consume fleet APIs but may not own fleet truth.
497
+ superseded_by: authorities.agent_operational_records
498
+ detect:
499
+ - 'n8n'
500
+ - id: activation-by-discovery
501
+ reason: A resolvable target is not permission to dispatch to it.
502
+ superseded_by: activation.execution_authority
503
+ detect:
504
+ - 'activation_by_discovery'
505
+ - 'auto_activate'
506
+ - 'activate_on_discovery'
507
+ - id: hard-coded-hermes-checkout-path
508
+ reason: Pinned releases are resolved from the registry, never from a path.
509
+ superseded_by: authorities.agent_operational_records
510
+ detect:
511
+ - '\$HOME/[^\s]*hermes'
512
+ - '~/[^\s]*hermes'
513
+ - '(?:^|/)code/hermes-agent'