@delorenj/pjangler 1.1.5 → 1.2.2
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/.mise/scripts/link-agentfiles.sh +9 -0
- package/dist/index.js +1492 -358
- package/dist/mcp-server.js +2391 -290
- package/package.json +5 -2
- package/templates/commonproject/.mise/scripts/create-plane-project.sh +26 -0
- package/templates/commonproject/copier.yml +2 -0
- package/templates/commonproject/template/.agents/hooks/README.md +151 -0
- package/templates/commonproject/template/.agents/hooks/hermes/hindsight-hook.sh +63 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-journal-write.sh +327 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-recall.sh +180 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-retain.sh +74 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-session-end.sh +57 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-bank.sh +57 -0
- package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-journal.sh +48 -0
- package/templates/commonproject/template/.agents/hooks/hooks.master.json +97 -0
- package/templates/commonproject/template/.agents/hooks/lib/hook-guard.sh +30 -0
- package/templates/commonproject/template/.agents/hooks/lib/local-config.sh +51 -0
- package/templates/commonproject/template/.agents/hooks/reminder-for-skill-check.sh +20 -0
- package/templates/commonproject/template/.agents/hooks/sync.py +618 -0
- package/templates/commonproject/template/.agents/local.example.json +15 -0
- package/templates/commonproject/template/.mise/scripts/hindsight-setup.sh +62 -0
- package/templates/commonproject/template/.mise/scripts/link-project-skills-to-clis.sh +110 -0
- package/templates/commonproject/template/.mise/scripts/unlink-project-skills-from-clis.sh +45 -0
- package/templates/commonproject/template/mise.toml.jinja +42 -0
- package/templates/hermes-agent/.codegraph/daemon.pid +6 -0
- package/templates/hermes-agent/.omo/run-continuation/ses_0e5b28303ffeXxL53hZjKggXDW.json +10 -0
- package/templates/hermes-agent/README.md +16 -14
- package/templates/hermes-agent/copier.yml +7 -25
- package/templates/hermes-agent/docs/architecture.md +16 -18
- package/templates/hermes-agent/docs/fleet-control-plane/README.md +35 -0
- package/templates/hermes-agent/docs/fleet-control-plane/architecture.md +253 -0
- package/templates/hermes-agent/docs/fleet-control-plane/epics-and-stories.md +280 -0
- package/templates/hermes-agent/docs/fleet-control-plane/implementation-readiness-report-2026-06-27.md +118 -0
- package/templates/hermes-agent/docs/fleet-control-plane/prd.md +141 -0
- package/templates/hermes-agent/docs/operations.md +17 -19
- package/templates/hermes-agent/docs/runbooks/runtime-checkpoint-repair.md +17 -13
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/README.md +47 -46
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/architecture.md +39 -38
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/development.md +63 -99
- package/templates/hermes-agent/docs/{scrum-master → sentinel}/providers.md +2 -2
- package/templates/hermes-agent/docs/sentinel.md +18 -0
- package/templates/hermes-agent/install-local.sh +22 -20
- package/templates/hermes-agent/runtime-scaffold/README.md +10 -9
- package/templates/hermes-agent/scripts/backfill-fleet-sot.sh +12 -21
- package/templates/hermes-agent/scripts/fleet-sync.sh +369 -0
- package/templates/hermes-agent/scripts/migrate-unify.sh +252 -0
- package/templates/hermes-agent/scripts/unify-pm.sh +148 -0
- package/templates/hermes-agent/template/.runtime-scaffold/README.md +10 -9
- package/templates/hermes-agent/template/.scripts/01-config.sh +2 -3
- package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -2
- package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +47 -19
- package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +71 -27
- package/templates/hermes-agent/template/.scripts/30-telegram.sh +3 -3
- package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +3 -3
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +48 -43
- package/templates/hermes-agent/template/.scripts/80-registry.sh +2 -2
- package/templates/hermes-agent/template/.scripts/99-summary.sh +3 -4
- package/templates/hermes-agent/template/.scripts/_lib.sh +4 -19
- package/templates/hermes-agent/template/.scripts/checkpoint.sh +36 -0
- package/templates/hermes-agent/template/.scripts/config.example.toml +11 -5
- package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.sh → heartbeat.sh} +84 -31
- package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +1 -1
- package/templates/hermes-agent/template/.scripts/providers/plane.sh +9 -3
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/emit-event.py +5 -5
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-autonomous-review.sh +6 -6
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-close-gate.sh +2 -2
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/autonomous-delegated-review.md +7 -7
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/bloodbank-events.md +3 -3
- package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/continuous-ticket-orchestration.md +6 -6
- package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.prompt.md.jinja → sentinel.prompt.md.jinja} +5 -4
- package/templates/hermes-agent/template/SOUL.md.jinja +3 -6
- package/templates/hermes-agent/template/hermes.jinja +6 -15
- package/templates/hermes-agent/template/role.yaml.jinja +9 -8
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/agent-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/module-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/agents/workflow-builder.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/agent.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/module.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmb/workflows/workflow.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/analyst.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/architect.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/dev.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/pm.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/quick-flow-solo-dev.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/sm.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/tea.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/tech-writer.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/agents/ux-designer.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/check-implementation-readiness.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/code-review.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/correct-course.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-architecture.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-epics-and-stories.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-dataflow.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-diagram.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-flowchart.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-wireframe.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-product-brief.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-story.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-ux-design.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/dev-story.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/document-project.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/generate-project-context.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/prd.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-dev.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-spec.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/research.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/retrospective.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-planning.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-status.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-atdd.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-automate.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-ci.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-framework.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-nfr.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-design.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-review.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-trace.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-init.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-status.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/agents/brainstorming-coach.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/creative-problem-solver.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/design-thinking-coach.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/innovation-strategist.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/presentation-master.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/agents/storyteller.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/design-thinking.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/innovation-strategy.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/problem-solving.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/cis/workflows/storytelling.md +0 -13
- package/templates/commonproject/.claude/commands/bmad/core/agents/bmad-master.md +0 -14
- package/templates/commonproject/.claude/commands/bmad/core/tasks/index-docs.md +0 -9
- package/templates/commonproject/.claude/commands/bmad/core/tasks/shard-doc.md +0 -9
- package/templates/commonproject/.claude/commands/bmad/core/workflows/brainstorming.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/core/workflows/party-mode.md +0 -5
- package/templates/commonproject/.claude/commands/bmad/custom/workflows/ticket-lifecycle.md +0 -5
- package/templates/hermes-agent/docs/scrum-master-sentinel.md +0 -17
- package/templates/hermes-agent/template/.scripts/75-scrum-master.sh +0 -117
- package/templates/hermes-agent/template/.scripts/90-chain-scrum-master.sh +0 -45
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
---
|
|
2
|
+
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8]
|
|
3
|
+
inputDocuments:
|
|
4
|
+
- docs/fleet-control-plane/prd.md
|
|
5
|
+
- docs/architecture.md
|
|
6
|
+
- docs/operations.md
|
|
7
|
+
workflowType: architecture
|
|
8
|
+
project_name: Fleet Control Plane
|
|
9
|
+
date: 2026-06-27
|
|
10
|
+
status: draft-ready
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Fleet Control Plane Architecture
|
|
14
|
+
|
|
15
|
+
## Executive Summary
|
|
16
|
+
|
|
17
|
+
The Fleet should stay multi-repo. The fix is not repo fusion. The fix is a
|
|
18
|
+
versioned Fleet contract, a single operational control plane in `pjangler`, and
|
|
19
|
+
an explicit orchestration split:
|
|
20
|
+
|
|
21
|
+
- `pjangler` is the source of control-plane truth.
|
|
22
|
+
- n8n is the visual workflow/orchestration plane.
|
|
23
|
+
- systemd is the local survival layer.
|
|
24
|
+
- `~/.hermes` remains live runtime state, not a template source.
|
|
25
|
+
|
|
26
|
+
## System Context
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
CommonProject
|
|
30
|
+
emits base project repo and .project.json
|
|
31
|
+
|
|
32
|
+
hermes-agent-template
|
|
33
|
+
emits agents/hermes/<role>, role.yaml, runtime scaffold, fallback units
|
|
34
|
+
|
|
35
|
+
pjangler
|
|
36
|
+
owns Fleet contract, schema validation, template status, fleet status,
|
|
37
|
+
reconciliation, migration, release gates, and n8n workflow generation
|
|
38
|
+
|
|
39
|
+
~/.hermes
|
|
40
|
+
owns fleet.env, auth, profiles, agents-registry.yaml, logs, state
|
|
41
|
+
|
|
42
|
+
n8n
|
|
43
|
+
runs visual Fleet workflows generated from pjangler and registry state
|
|
44
|
+
|
|
45
|
+
systemd --user
|
|
46
|
+
keeps gateway, consumer, and local fallback heartbeat/checkpoint alive
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Architecture Decisions
|
|
50
|
+
|
|
51
|
+
### ADR-001: Keep Repos Independent, Bind With Fleet Contract
|
|
52
|
+
|
|
53
|
+
Decision: Keep `CommonProject`, `hermes-agent-template`, `pjangler`, and Hermes
|
|
54
|
+
engine as separate repos.
|
|
55
|
+
|
|
56
|
+
Rationale:
|
|
57
|
+
|
|
58
|
+
- Each repo has a valid standalone reason to exist.
|
|
59
|
+
- The coupling problem is contract visibility, not physical repo layout.
|
|
60
|
+
- Independent release cadence matters because templates, runtime state, and
|
|
61
|
+
orchestration logic change at different speeds.
|
|
62
|
+
|
|
63
|
+
Consequences:
|
|
64
|
+
|
|
65
|
+
- Add `fleet-contract.yaml` and schema validation.
|
|
66
|
+
- `pjangler` must report effective sources and versions instead of relying on
|
|
67
|
+
hidden local assumptions.
|
|
68
|
+
|
|
69
|
+
### ADR-002: Make pjangler the Fleet Control Plane
|
|
70
|
+
|
|
71
|
+
Decision: `pjangler` owns Fleet-wide inspection, validation, reconciliation,
|
|
72
|
+
template pinning, migration, and n8n workflow generation.
|
|
73
|
+
|
|
74
|
+
Rationale:
|
|
75
|
+
|
|
76
|
+
- `pjangler` already bootstraps projects and Hermes agents.
|
|
77
|
+
- It already vendors templates and owns parity/migration logic.
|
|
78
|
+
- It is the right place for deterministic CLI checks and MCP surfaces.
|
|
79
|
+
|
|
80
|
+
Consequences:
|
|
81
|
+
|
|
82
|
+
- `pjangler` must stop being ambiguous about whether vendored templates are
|
|
83
|
+
release inputs, development overrides, or dirty experiments.
|
|
84
|
+
- Publish and build paths need dirty-template gates.
|
|
85
|
+
|
|
86
|
+
### ADR-003: n8n Is the Visual Orchestration Plane, Not the Source of Truth
|
|
87
|
+
|
|
88
|
+
Decision: n8n coordinates Fleet workflows but reads truth from `pjangler`,
|
|
89
|
+
`fleet-contract.yaml`, and `~/.hermes/agents-registry.yaml`.
|
|
90
|
+
|
|
91
|
+
Rationale:
|
|
92
|
+
|
|
93
|
+
- n8n gives the desired visual control plane for delegation and health flows.
|
|
94
|
+
- Letting n8n own state would create another drift surface.
|
|
95
|
+
- Generated workflows are easier to review and reproduce than hand-edited
|
|
96
|
+
workflow state.
|
|
97
|
+
|
|
98
|
+
Consequences:
|
|
99
|
+
|
|
100
|
+
- First implementation should use generated n8n workflows with Webhook,
|
|
101
|
+
Schedule Trigger, HTTP Request, Set/If/Switch/Merge, and minimal Code nodes.
|
|
102
|
+
- Custom n8n nodes can come later if workflow generation proves stable.
|
|
103
|
+
- Workflow code must be validated before creation or update.
|
|
104
|
+
|
|
105
|
+
### ADR-004: Hybrid Heartbeat Strategy
|
|
106
|
+
|
|
107
|
+
Decision: Implement heartbeat v2 as n8n-centralized orchestration with systemd
|
|
108
|
+
local fallback.
|
|
109
|
+
|
|
110
|
+
Rationale:
|
|
111
|
+
|
|
112
|
+
- n8n-only would make the Fleet fragile when n8n is down.
|
|
113
|
+
- systemd-only hides orchestration and makes delegation hard to visualize.
|
|
114
|
+
- Hybrid gives visual control without sacrificing local survival.
|
|
115
|
+
|
|
116
|
+
Consequences:
|
|
117
|
+
|
|
118
|
+
- systemd keeps gateway and consumer services running.
|
|
119
|
+
- systemd fallback performs minimal self-health and checkpoint behavior.
|
|
120
|
+
- n8n performs supervisor flows, agent health fanout, delegation, and
|
|
121
|
+
reconciliation triggers.
|
|
122
|
+
|
|
123
|
+
### ADR-005: Treat Managed Exceptions as First-Class Fleet Entries
|
|
124
|
+
|
|
125
|
+
Decision: Profiles and services outside the standard PM-agent pattern must be
|
|
126
|
+
represented as explicit managed exceptions instead of undocumented drift.
|
|
127
|
+
|
|
128
|
+
Rationale:
|
|
129
|
+
|
|
130
|
+
- Voice agents, adversarial-review profiles, and historical profiles can be
|
|
131
|
+
legitimate without matching the PM template.
|
|
132
|
+
- Drift reports are useful only when they distinguish bugs from exceptions.
|
|
133
|
+
|
|
134
|
+
Consequences:
|
|
135
|
+
|
|
136
|
+
- Registry schema gets `managed`, `kind`, `source`, `owner`, and `notes`.
|
|
137
|
+
- `pj fleet status` reports unmanaged/external entries separately from broken
|
|
138
|
+
managed entries.
|
|
139
|
+
|
|
140
|
+
## Fleet Contract
|
|
141
|
+
|
|
142
|
+
Initial contract shape:
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
schema_version: 1
|
|
146
|
+
fleet_contract_version: 1
|
|
147
|
+
service_model: hybrid-n8n-systemd
|
|
148
|
+
templates:
|
|
149
|
+
commonproject:
|
|
150
|
+
source: git@github.com:delorenj/CommonProject.git
|
|
151
|
+
required_clean: true
|
|
152
|
+
hermes_agent:
|
|
153
|
+
source: git@github.com:delorenj/hermes-agent-template.git
|
|
154
|
+
required_clean: true
|
|
155
|
+
schemas:
|
|
156
|
+
project_json: 1
|
|
157
|
+
role_yaml: 1
|
|
158
|
+
agents_registry: 2
|
|
159
|
+
profile_yaml: 1
|
|
160
|
+
n8n:
|
|
161
|
+
mode: generated-workflows
|
|
162
|
+
source_of_truth: pjangler
|
|
163
|
+
systemd:
|
|
164
|
+
fallback: true
|
|
165
|
+
required_units:
|
|
166
|
+
- gateway
|
|
167
|
+
- consumer
|
|
168
|
+
- fallback-heartbeat
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## n8n Workflow Model
|
|
172
|
+
|
|
173
|
+
### Supervisor Workflow
|
|
174
|
+
|
|
175
|
+
Trigger:
|
|
176
|
+
|
|
177
|
+
- Schedule Trigger for periodic health.
|
|
178
|
+
- Webhook for manual or external Fleet events.
|
|
179
|
+
|
|
180
|
+
Flow:
|
|
181
|
+
|
|
182
|
+
1. Fetch Fleet status from `pjangler`.
|
|
183
|
+
2. Normalize registry/profile/systemd rows.
|
|
184
|
+
3. Split into managed agents and managed exceptions.
|
|
185
|
+
4. Branch by status: healthy, drift, degraded, manual.
|
|
186
|
+
5. Trigger targeted reconcile or notify operator.
|
|
187
|
+
6. Respond with a concise Fleet summary.
|
|
188
|
+
|
|
189
|
+
Design rules:
|
|
190
|
+
|
|
191
|
+
- Normalize data before branch convergence.
|
|
192
|
+
- Avoid accidental item-count fanout; use execute-once where independent calls
|
|
193
|
+
do not need per-agent items.
|
|
194
|
+
- Prefer Set/If/Switch/Merge over Code nodes when possible.
|
|
195
|
+
- Use HTTP Request for internal `pjangler`/Hermes APIs until dedicated nodes are
|
|
196
|
+
justified.
|
|
197
|
+
|
|
198
|
+
### Per-Agent Workflow
|
|
199
|
+
|
|
200
|
+
Trigger:
|
|
201
|
+
|
|
202
|
+
- Supervisor dispatch.
|
|
203
|
+
- Bloodbank or internal webhook command.
|
|
204
|
+
|
|
205
|
+
Flow:
|
|
206
|
+
|
|
207
|
+
1. Load one agent entry.
|
|
208
|
+
2. Check gateway, consumer, fallback heartbeat, profile symlink, runtime repo,
|
|
209
|
+
and role manifest.
|
|
210
|
+
3. If safe drift exists, call `pj fleet reconcile --agent <id> --apply`.
|
|
211
|
+
4. If unsafe drift exists, emit manual action.
|
|
212
|
+
5. Record result for supervisor.
|
|
213
|
+
|
|
214
|
+
## Command Surface
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
pj templates status [--json]
|
|
218
|
+
pj fleet status [--json] [--agent <id>]
|
|
219
|
+
pj fleet reconcile [--dry-run] [--apply] [--agent <id>]
|
|
220
|
+
pj fleet validate [--json]
|
|
221
|
+
pj fleet n8n export [--workflow supervisor|agent] [--json]
|
|
222
|
+
pj fleet n8n validate
|
|
223
|
+
pj fleet n8n create --name <workflow>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Data and Schema Ownership
|
|
227
|
+
|
|
228
|
+
- `.project.json`: owned by CommonProject and pjangler migrations.
|
|
229
|
+
- `role.yaml`: owned by hermes-agent-template, validated by pjangler.
|
|
230
|
+
- `agents-registry.yaml`: owned by Fleet runtime/provisioning, reconciled by
|
|
231
|
+
pjangler.
|
|
232
|
+
- `profile.yaml`: owned by Hermes runtime, validated for inheritance metadata.
|
|
233
|
+
- `fleet-contract.yaml`: owned by pjangler and committed in the control-plane
|
|
234
|
+
repo.
|
|
235
|
+
|
|
236
|
+
## Current Drift Repair Targets
|
|
237
|
+
|
|
238
|
+
- Dirty vendored `templates/hermes-agent` must be promoted or reverted.
|
|
239
|
+
- Heartbeat v2 must become a deliberate contract, not a dirty submodule state.
|
|
240
|
+
- `runtime_scaffold_dir` must point at an existing fallback path.
|
|
241
|
+
- Registry Hermes paths must be refreshed from `fleet.env`.
|
|
242
|
+
- Invalid generated role model fields such as `model.name: "plane"` must fail
|
|
243
|
+
schema validation.
|
|
244
|
+
|
|
245
|
+
## Rollout Strategy
|
|
246
|
+
|
|
247
|
+
1. Add schemas and read-only status commands.
|
|
248
|
+
2. Add dirty-template gates.
|
|
249
|
+
3. Add safe reconcile for wrapper/profile/registry path drift.
|
|
250
|
+
4. Promote heartbeat v2 contract and systemd fallback behavior.
|
|
251
|
+
5. Generate and validate n8n supervisor workflow.
|
|
252
|
+
6. Enable workflow creation only after exported workflow validation passes.
|
|
253
|
+
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
stepsCompleted: [1, 2, 3, 4]
|
|
3
|
+
inputDocuments:
|
|
4
|
+
- docs/fleet-control-plane/prd.md
|
|
5
|
+
- docs/fleet-control-plane/architecture.md
|
|
6
|
+
workflowType: epics-and-stories
|
|
7
|
+
project_name: Fleet Control Plane
|
|
8
|
+
date: 2026-06-27
|
|
9
|
+
status: draft-ready
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Fleet Control Plane - Epic Breakdown
|
|
13
|
+
|
|
14
|
+
## Requirements Inventory
|
|
15
|
+
|
|
16
|
+
### Functional Requirements
|
|
17
|
+
|
|
18
|
+
- FR1: Define a versioned Fleet contract.
|
|
19
|
+
- FR2: Report effective template source, commit, tag, and dirty state.
|
|
20
|
+
- FR3: Report registry/profile/role/systemd/fleet env drift.
|
|
21
|
+
- FR4: Reconcile safe drift through dry-run and explicit apply modes.
|
|
22
|
+
- FR5: Support managed exceptions.
|
|
23
|
+
- FR6: Validate core manifests with schemas.
|
|
24
|
+
- FR7: Block release on dirty vendored templates.
|
|
25
|
+
- FR8: Implement n8n plus systemd hybrid heartbeat.
|
|
26
|
+
- FR9: Keep n8n as orchestration, not source of truth.
|
|
27
|
+
- FR10: Generate and validate n8n workflows.
|
|
28
|
+
- FR11: Repair known current drift.
|
|
29
|
+
- FR12: Keep default commands read-only.
|
|
30
|
+
|
|
31
|
+
### Non-Functional Requirements
|
|
32
|
+
|
|
33
|
+
- NFR1: Default to dry-run/read-only.
|
|
34
|
+
- NFR2: Never destroy ambiguous runtime state automatically.
|
|
35
|
+
- NFR3: Keep local fallback alive when n8n is down.
|
|
36
|
+
- NFR4: Produce deterministic, grep-friendly output.
|
|
37
|
+
- NFR5: Support CLI and npm release gates.
|
|
38
|
+
- NFR6: Keep secrets out of committed artifacts.
|
|
39
|
+
- NFR7: Preserve fast solo iteration.
|
|
40
|
+
- NFR8: Validate n8n workflows before creation.
|
|
41
|
+
|
|
42
|
+
## Epic List
|
|
43
|
+
|
|
44
|
+
1. Fleet contract and schema foundation.
|
|
45
|
+
2. Template source status and release gates.
|
|
46
|
+
3. Fleet status and reconciliation.
|
|
47
|
+
4. Hybrid heartbeat and n8n workflow generation.
|
|
48
|
+
5. Drift repair and rollout hardening.
|
|
49
|
+
|
|
50
|
+
## Epic 1: Fleet Contract and Schema Foundation
|
|
51
|
+
|
|
52
|
+
Goal: Establish the explicit contract that all other implementation work checks
|
|
53
|
+
against.
|
|
54
|
+
|
|
55
|
+
### Story 1.1: Add Fleet Contract Schema
|
|
56
|
+
|
|
57
|
+
As the Fleet operator, I want a committed Fleet contract schema so that template
|
|
58
|
+
versions, service model, and manifest versions are explicit.
|
|
59
|
+
|
|
60
|
+
Acceptance Criteria:
|
|
61
|
+
|
|
62
|
+
- Given the repo contains no Fleet contract, when `pj fleet validate` runs, then
|
|
63
|
+
it reports the missing contract clearly.
|
|
64
|
+
- Given a valid `fleet-contract.yaml`, when validation runs, then schema version,
|
|
65
|
+
service model, template entries, and schema versions pass.
|
|
66
|
+
- Given an unsupported service model, when validation runs, then the command
|
|
67
|
+
fails with the invalid value and allowed values.
|
|
68
|
+
|
|
69
|
+
### Story 1.2: Add Manifest Schemas
|
|
70
|
+
|
|
71
|
+
As an implementer, I want schemas for `.project.json`, `role.yaml`,
|
|
72
|
+
`agents-registry.yaml`, and `profile.yaml` so invalid generated state fails
|
|
73
|
+
early.
|
|
74
|
+
|
|
75
|
+
Acceptance Criteria:
|
|
76
|
+
|
|
77
|
+
- Given `role.yaml` has `model.provider: ""` and `model.name: "plane"`, when
|
|
78
|
+
validation runs, then it reports an invalid model override.
|
|
79
|
+
- Given registry entries lack exception metadata for non-standard profiles, when
|
|
80
|
+
validation runs, then they are classified as unmanaged drift.
|
|
81
|
+
- Given profile metadata includes `config.inherit_from: default` and
|
|
82
|
+
`save_mode: delta`, when validation runs, then inheritance contract passes.
|
|
83
|
+
|
|
84
|
+
### Story 1.3: Add Managed Exception Model
|
|
85
|
+
|
|
86
|
+
As the Fleet operator, I want explicit managed exceptions so that special
|
|
87
|
+
profiles do not pollute drift reports.
|
|
88
|
+
|
|
89
|
+
Acceptance Criteria:
|
|
90
|
+
|
|
91
|
+
- Given a voice-agent profile exists outside the PM scaffold, when it is marked
|
|
92
|
+
`managed: false` and `kind: voice-agent`, then `pj fleet status` reports it
|
|
93
|
+
under exceptions.
|
|
94
|
+
- Given an unregistered profile exists without exception metadata, when status
|
|
95
|
+
runs, then it reports manual classification required.
|
|
96
|
+
- Given an exception has notes, when status runs with `--json`, then notes are
|
|
97
|
+
included.
|
|
98
|
+
|
|
99
|
+
## Epic 2: Template Source Status and Release Gates
|
|
100
|
+
|
|
101
|
+
Goal: Make template bytes and release safety visible.
|
|
102
|
+
|
|
103
|
+
### Story 2.1: Implement `pj templates status`
|
|
104
|
+
|
|
105
|
+
As the Fleet operator, I want to see effective template sources so I know which
|
|
106
|
+
bytes provisioning will use.
|
|
107
|
+
|
|
108
|
+
Acceptance Criteria:
|
|
109
|
+
|
|
110
|
+
- Given `PJANGLER_HERMES_TEMPLATE` is set, when status runs, then it reports the
|
|
111
|
+
env override as effective source.
|
|
112
|
+
- Given vendored templates exist, when status runs, then it reports commit,
|
|
113
|
+
branch, dirty state, and submodule path.
|
|
114
|
+
- Given local template checkout exists but vendored template takes precedence,
|
|
115
|
+
when status runs, then it shows both and explains precedence.
|
|
116
|
+
|
|
117
|
+
### Story 2.2: Add Dirty Vendored Template Gate
|
|
118
|
+
|
|
119
|
+
As a package maintainer, I want publish/build to fail on dirty vendored
|
|
120
|
+
templates so experiments do not ship accidentally.
|
|
121
|
+
|
|
122
|
+
Acceptance Criteria:
|
|
123
|
+
|
|
124
|
+
- Given `templates/hermes-agent` has modified files, when `npm run prepublishOnly`
|
|
125
|
+
runs, then it fails before packaging.
|
|
126
|
+
- Given a submodule pointer changed cleanly and is committed, when the gate runs,
|
|
127
|
+
then it passes.
|
|
128
|
+
- Given generated runtime submodule changes are present, when the gate runs, then
|
|
129
|
+
it reports them separately from template dirtiness.
|
|
130
|
+
|
|
131
|
+
### Story 2.3: Add Template Drift Guidance
|
|
132
|
+
|
|
133
|
+
As an implementer, I want actionable drift messages so I know whether to promote
|
|
134
|
+
or revert template changes.
|
|
135
|
+
|
|
136
|
+
Acceptance Criteria:
|
|
137
|
+
|
|
138
|
+
- Given vendored `templates/hermes-agent` differs from `~/code/hermes-agent-template`,
|
|
139
|
+
when status runs, then it recommends promote, update pointer, or discard.
|
|
140
|
+
- Given CommonProject vendored commit lags local checkout, when status runs, then
|
|
141
|
+
it reports pinned-vs-local delta without failing by default.
|
|
142
|
+
- Given `--strict` is passed, when local and vendored template commits differ,
|
|
143
|
+
then the command exits non-zero.
|
|
144
|
+
|
|
145
|
+
## Epic 3: Fleet Status and Reconciliation
|
|
146
|
+
|
|
147
|
+
Goal: Turn implicit Fleet drift into deterministic status and safe repair.
|
|
148
|
+
|
|
149
|
+
### Story 3.1: Implement `pj fleet status`
|
|
150
|
+
|
|
151
|
+
As the Fleet operator, I want one command to compare registry, profiles,
|
|
152
|
+
role manifests, fleet env, runtime repos, and systemd units.
|
|
153
|
+
|
|
154
|
+
Acceptance Criteria:
|
|
155
|
+
|
|
156
|
+
- Given registry and profile symlink agree, when status runs, then the agent is
|
|
157
|
+
healthy for that check.
|
|
158
|
+
- Given a registry entry points at a stale Hermes binary path, when status runs,
|
|
159
|
+
then it reports stale metadata and the effective `fleet.env` path.
|
|
160
|
+
- Given systemd units are checkpoint-era while the contract says heartbeat-era,
|
|
161
|
+
when status runs, then it reports service model drift.
|
|
162
|
+
|
|
163
|
+
### Story 3.2: Implement Safe `pj fleet reconcile`
|
|
164
|
+
|
|
165
|
+
As the Fleet operator, I want safe drift repaired explicitly so routine fixes
|
|
166
|
+
are repeatable.
|
|
167
|
+
|
|
168
|
+
Acceptance Criteria:
|
|
169
|
+
|
|
170
|
+
- Given a wrapper differs from the template and no runtime state is at risk, when
|
|
171
|
+
`--apply` runs, then the wrapper is regenerated.
|
|
172
|
+
- Given a profile path is a real directory where a symlink is expected, when
|
|
173
|
+
reconcile runs, then it reports manual action and does not delete anything.
|
|
174
|
+
- Given runtime `profile.yaml` is missing inherited config metadata, when
|
|
175
|
+
`--apply` runs, then metadata is inserted without removing other fields.
|
|
176
|
+
|
|
177
|
+
### Story 3.3: Add Current Drift Repair Commands
|
|
178
|
+
|
|
179
|
+
As the Fleet operator, I want known current drift addressed by idempotent repair
|
|
180
|
+
paths.
|
|
181
|
+
|
|
182
|
+
Acceptance Criteria:
|
|
183
|
+
|
|
184
|
+
- Given config fallback `runtime_scaffold_dir` points at a missing path, when
|
|
185
|
+
repair runs, then it updates to an existing template scaffold path.
|
|
186
|
+
- Given registry entries have stale Hermes paths, when repair runs, then they
|
|
187
|
+
update from `fleet.env`.
|
|
188
|
+
- Given invalid `role.yaml` model override exists, when repair runs, then it
|
|
189
|
+
removes or corrects the bad override.
|
|
190
|
+
|
|
191
|
+
## Epic 4: Hybrid Heartbeat and n8n Workflow Generation
|
|
192
|
+
|
|
193
|
+
Goal: Promote heartbeat v2 deliberately as n8n orchestration plus systemd
|
|
194
|
+
fallback.
|
|
195
|
+
|
|
196
|
+
### Story 4.1: Define Heartbeat v2 Contract
|
|
197
|
+
|
|
198
|
+
As the Fleet operator, I want heartbeat v2 specified so checkpoint and heartbeat
|
|
199
|
+
models do not coexist accidentally.
|
|
200
|
+
|
|
201
|
+
Acceptance Criteria:
|
|
202
|
+
|
|
203
|
+
- Given `service_model: hybrid-n8n-systemd`, when validation runs, then required
|
|
204
|
+
gateway, consumer, and fallback heartbeat expectations are checked.
|
|
205
|
+
- Given a checkpoint-only agent exists during migration, when status runs, then
|
|
206
|
+
it is classified as legacy rather than broken.
|
|
207
|
+
- Given a heartbeat-enabled agent exists, when status runs, then n8n registration
|
|
208
|
+
and systemd fallback are both checked.
|
|
209
|
+
|
|
210
|
+
### Story 4.2: Export n8n Supervisor Workflow
|
|
211
|
+
|
|
212
|
+
As the Fleet operator, I want `pjangler` to generate an n8n supervisor workflow
|
|
213
|
+
so orchestration is reviewable and reproducible.
|
|
214
|
+
|
|
215
|
+
Acceptance Criteria:
|
|
216
|
+
|
|
217
|
+
- Given Fleet status JSON, when workflow export runs, then the generated
|
|
218
|
+
workflow normalizes agent rows before branching.
|
|
219
|
+
- Given n8n workflow validation is available, when `pj fleet n8n validate` runs,
|
|
220
|
+
then it validates generated code before any workflow is created.
|
|
221
|
+
- Given n8n is unavailable, when export runs, then local workflow code is still
|
|
222
|
+
generated without creating remote state.
|
|
223
|
+
|
|
224
|
+
### Story 4.3: Add Per-Agent n8n Workflow Pattern
|
|
225
|
+
|
|
226
|
+
As the Fleet operator, I want per-agent workflows so health and delegation can
|
|
227
|
+
be visualized without hand-wiring every agent.
|
|
228
|
+
|
|
229
|
+
Acceptance Criteria:
|
|
230
|
+
|
|
231
|
+
- Given an agent id, when per-agent workflow export runs, then workflow input is
|
|
232
|
+
scoped to one registry entry.
|
|
233
|
+
- Given safe drift is found, when the workflow is executed, then it calls the
|
|
234
|
+
dry-run reconcile path first.
|
|
235
|
+
- Given unsafe drift is found, when the workflow is executed, then it emits a
|
|
236
|
+
manual action instead of applying changes.
|
|
237
|
+
|
|
238
|
+
## Epic 5: Rollout Hardening
|
|
239
|
+
|
|
240
|
+
Goal: Make the migration safe enough to run on the live Fleet.
|
|
241
|
+
|
|
242
|
+
### Story 5.1: Add Readiness Gates
|
|
243
|
+
|
|
244
|
+
As the Fleet operator, I want a single readiness command so I know when
|
|
245
|
+
implementation is ready for live Fleet rollout.
|
|
246
|
+
|
|
247
|
+
Acceptance Criteria:
|
|
248
|
+
|
|
249
|
+
- Given schemas, status, reconcile dry-run, template gate, and n8n validation
|
|
250
|
+
pass, when readiness runs, then it reports ready.
|
|
251
|
+
- Given any current drift remains unresolved, when readiness runs, then it lists
|
|
252
|
+
blockers by agent or file.
|
|
253
|
+
- Given managed exceptions exist, when readiness runs, then it excludes them
|
|
254
|
+
from blockers and includes them in a separate exception count.
|
|
255
|
+
|
|
256
|
+
### Story 5.2: Document Operator Runbook
|
|
257
|
+
|
|
258
|
+
As a future agent/operator, I want a runbook so rollout and rollback are clear.
|
|
259
|
+
|
|
260
|
+
Acceptance Criteria:
|
|
261
|
+
|
|
262
|
+
- Given the runbook, a reader can run status, validation, export, dry-run
|
|
263
|
+
reconcile, apply reconcile, and rollback.
|
|
264
|
+
- Given n8n is down, the runbook explains systemd fallback verification.
|
|
265
|
+
- Given a dirty vendored template blocks release, the runbook explains promote
|
|
266
|
+
versus revert choices.
|
|
267
|
+
|
|
268
|
+
### Story 5.3: Smoke Test Against Live Fleet
|
|
269
|
+
|
|
270
|
+
As the Fleet operator, I want proof against real local state before marking the
|
|
271
|
+
work done.
|
|
272
|
+
|
|
273
|
+
Acceptance Criteria:
|
|
274
|
+
|
|
275
|
+
- Given the live registry, when status runs, then it completes and returns JSON.
|
|
276
|
+
- Given a selected low-risk agent, when reconcile dry-run runs, then it reports
|
|
277
|
+
expected changes without mutation.
|
|
278
|
+
- Given n8n workflow code is generated, when validation runs, then no workflow is
|
|
279
|
+
created until validation succeeds.
|
|
280
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
stepsCompleted: [1, 2, 3, 4, 5, 6]
|
|
3
|
+
inputDocuments:
|
|
4
|
+
- docs/fleet-control-plane/prd.md
|
|
5
|
+
- docs/fleet-control-plane/architecture.md
|
|
6
|
+
- docs/fleet-control-plane/epics-and-stories.md
|
|
7
|
+
workflowType: implementation-readiness
|
|
8
|
+
project_name: Fleet Control Plane
|
|
9
|
+
date: 2026-06-27
|
|
10
|
+
status: ready-with-known-blockers
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Implementation Readiness Assessment Report
|
|
14
|
+
|
|
15
|
+
**Date:** 2026-06-27
|
|
16
|
+
**Project:** Fleet Control Plane
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
The implementation plan is coherent and ready to begin, with known blockers that
|
|
21
|
+
should be handled in the first implementation epic rather than deferred.
|
|
22
|
+
|
|
23
|
+
The strongest architecture choice is the hybrid model:
|
|
24
|
+
|
|
25
|
+
- n8n coordinates Fleet workflows visually.
|
|
26
|
+
- `pjangler` remains the control-plane and validation source.
|
|
27
|
+
- systemd keeps local survival behavior in place.
|
|
28
|
+
|
|
29
|
+
## Document Inventory
|
|
30
|
+
|
|
31
|
+
- PRD: `docs/fleet-control-plane/prd.md`
|
|
32
|
+
- Architecture: `docs/fleet-control-plane/architecture.md`
|
|
33
|
+
- Epics and stories: `docs/fleet-control-plane/epics-and-stories.md`
|
|
34
|
+
- Existing operational docs: `docs/architecture.md`, `docs/operations.md`
|
|
35
|
+
|
|
36
|
+
## Alignment Review
|
|
37
|
+
|
|
38
|
+
### PRD to Architecture
|
|
39
|
+
|
|
40
|
+
Pass. Each major requirement maps to an architecture decision:
|
|
41
|
+
|
|
42
|
+
- Fleet contract maps to ADR-001.
|
|
43
|
+
- `pjangler` control plane maps to ADR-002.
|
|
44
|
+
- n8n orchestration maps to ADR-003.
|
|
45
|
+
- hybrid heartbeat maps to ADR-004.
|
|
46
|
+
- managed exceptions map to ADR-005.
|
|
47
|
+
|
|
48
|
+
### Architecture to Epics
|
|
49
|
+
|
|
50
|
+
Pass. The epics cover the required implementation sequence:
|
|
51
|
+
|
|
52
|
+
1. Define contract and schemas.
|
|
53
|
+
2. Make template sources visible and gated.
|
|
54
|
+
3. Add status and reconcile.
|
|
55
|
+
4. Promote heartbeat v2 and generate n8n workflows.
|
|
56
|
+
5. Harden rollout.
|
|
57
|
+
|
|
58
|
+
### Risk Coverage
|
|
59
|
+
|
|
60
|
+
Mostly pass. The plan explicitly covers:
|
|
61
|
+
|
|
62
|
+
- n8n outage fallback.
|
|
63
|
+
- dirty vendored templates.
|
|
64
|
+
- stale registry paths.
|
|
65
|
+
- ambiguous profile/runtime state.
|
|
66
|
+
- workflow validation before creation.
|
|
67
|
+
- managed exceptions.
|
|
68
|
+
|
|
69
|
+
Remaining risk: exact n8n workflow node parameters must be validated during
|
|
70
|
+
implementation using the n8n workflow SDK before creating live workflows.
|
|
71
|
+
|
|
72
|
+
## Known Blockers to Resolve First
|
|
73
|
+
|
|
74
|
+
1. Dirty vendored `pjangler/templates/hermes-agent` currently contains heartbeat
|
|
75
|
+
v2 changes that are not cleanly promoted into `hermes-agent-template`.
|
|
76
|
+
2. Current `hermes-agent-template` clean tree still describes checkpoint timers,
|
|
77
|
+
while pjangler parity expects heartbeat timers.
|
|
78
|
+
3. `~/.config/hermes-agent-template/config.toml` has a missing fallback scaffold
|
|
79
|
+
path.
|
|
80
|
+
4. `~/.hermes/agents-registry.yaml` contains stale Hermes path metadata.
|
|
81
|
+
5. Some profiles exist outside registry coverage and need managed exception
|
|
82
|
+
classification.
|
|
83
|
+
6. At least one generated role manifest has invalid model fields.
|
|
84
|
+
|
|
85
|
+
## Readiness Decision
|
|
86
|
+
|
|
87
|
+
Status: ready to implement Epic 1.
|
|
88
|
+
|
|
89
|
+
Do not start live n8n workflow creation until these gates are available:
|
|
90
|
+
|
|
91
|
+
- Schema validation exists.
|
|
92
|
+
- Template status reports clean/dirty state.
|
|
93
|
+
- Fleet status can run read-only against the live registry.
|
|
94
|
+
- n8n workflow export can be validated without creating remote workflows.
|
|
95
|
+
|
|
96
|
+
## First Implementation Slice
|
|
97
|
+
|
|
98
|
+
The first slice should be deliberately boring:
|
|
99
|
+
|
|
100
|
+
1. Add `fleet-contract.yaml` draft and schema.
|
|
101
|
+
2. Add manifest schemas.
|
|
102
|
+
3. Add `pj templates status --json`.
|
|
103
|
+
4. Add dirty vendored template detection.
|
|
104
|
+
5. Add `pj fleet status --json` with read-only checks only.
|
|
105
|
+
|
|
106
|
+
This gives immediate visibility and reduces risk before any mutating reconcile
|
|
107
|
+
or n8n creation work begins.
|
|
108
|
+
|
|
109
|
+
## Implementation Exit Gates
|
|
110
|
+
|
|
111
|
+
- All schema tests pass.
|
|
112
|
+
- `pj templates status --json` reports no unclassified dirty template state.
|
|
113
|
+
- `pj fleet status --json` reports all managed drift with stable identifiers.
|
|
114
|
+
- Managed exceptions are explicitly recorded.
|
|
115
|
+
- `pj fleet reconcile` defaults to dry-run.
|
|
116
|
+
- n8n workflow code validates before creation.
|
|
117
|
+
- Existing docs are updated to reflect heartbeat v2 or checkpoint legacy mode.
|
|
118
|
+
|