cloving 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +329 -215
- package/dist/src/agent-harness-shell.d.ts +2 -1
- package/dist/src/agent-harness-shell.js +8 -5
- package/dist/src/authority/command-wait-checks.d.ts +8 -0
- package/dist/src/authority/command-wait-checks.js +88 -0
- package/dist/src/authority/command-wait-results.d.ts +15 -0
- package/dist/src/authority/command-wait-results.js +73 -0
- package/dist/src/authority/command-wait-view.d.ts +21 -0
- package/dist/src/authority/command-wait-view.js +34 -0
- package/dist/src/authority/command-waits.d.ts +39 -0
- package/dist/src/authority/command-waits.js +97 -0
- package/dist/src/authority/commands.js +22 -1
- package/dist/src/authority/dispatch-decision.d.ts +8 -0
- package/dist/src/authority/dispatch-decision.js +26 -1
- package/dist/src/authority/effect-requests.js +6 -3
- package/dist/src/authority/effect-results.js +4 -2
- package/dist/src/authority/history-state.d.ts +2 -0
- package/dist/src/authority/history-state.js +13 -1
- package/dist/src/authority/instants.d.ts +1 -0
- package/dist/src/authority/instants.js +21 -0
- package/dist/src/authority/reduction-state.d.ts +2 -0
- package/dist/src/authority/reduction-state.js +5 -0
- package/dist/src/authority/reduction.js +24 -0
- package/dist/src/authority/status-input.d.ts +2 -0
- package/dist/src/authority/status.d.ts +2 -0
- package/dist/src/authority/status.js +1 -0
- package/dist/src/authority/stop-sequence.d.ts +1 -0
- package/dist/src/authority/stop-sequence.js +2 -1
- package/dist/src/authority/transitions.d.ts +6 -4
- package/dist/src/authority/transitions.js +7 -0
- package/dist/src/broker/actor/authority-health.d.ts +9 -0
- package/dist/src/broker/actor/authority-health.js +24 -0
- package/dist/src/broker/actor/authority-queries.d.ts +2 -1
- package/dist/src/broker/actor/authority-queries.js +14 -5
- package/dist/src/broker/actor/authority-receipts.js +1 -1
- package/dist/src/broker/actor/authority-runtime.d.ts +4 -2
- package/dist/src/broker/actor/authority-runtime.js +29 -20
- package/dist/src/broker/actor/authority-session.d.ts +6 -19
- package/dist/src/broker/actor/authority-session.js +66 -88
- package/dist/src/broker/actor/authority-settings.d.ts +2 -1
- package/dist/src/broker/actor/authority-settings.js +6 -3
- package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
- package/dist/src/broker/actor/authority-upgrades.js +8 -2
- package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
- package/dist/src/broker/actor/authority-watchdog.js +31 -9
- package/dist/src/broker/actor/authority.js +3 -1
- package/dist/src/broker/actor/delivery-intents.js +2 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
- package/dist/src/broker/actor/effect-delivery.js +15 -2
- package/dist/src/broker/actor/effect-plan.js +11 -2
- package/dist/src/broker/actor/effect-queries.d.ts +4 -0
- package/dist/src/broker/actor/effect-queries.js +9 -1
- package/dist/src/broker/actor/effect-turn.js +2 -0
- package/dist/src/broker/actor/projection-memory.d.ts +43 -0
- package/dist/src/broker/actor/projection-memory.js +207 -0
- package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
- package/dist/src/broker/actor/runtime-parts.js +8 -3
- package/dist/src/broker/actor/stop-plan.js +9 -3
- package/dist/src/broker/actor/stop-turn.d.ts +2 -0
- package/dist/src/broker/actor/stop-turn.js +24 -11
- package/dist/src/broker/actor/turn-draft.d.ts +1 -0
- package/dist/src/broker/actor/turn-draft.js +4 -0
- package/dist/src/broker/actor/turn-state.js +5 -1
- package/dist/src/broker/authority-admission.js +60 -0
- package/dist/src/broker/authority-restore.d.ts +2 -0
- package/dist/src/broker/authority-restore.js +35 -1
- package/dist/src/broker/command-wait-restore.d.ts +31 -0
- package/dist/src/broker/command-wait-restore.js +86 -0
- package/dist/src/broker/decision-restore.d.ts +1 -1
- package/dist/src/broker/decision-restore.js +1 -0
- package/dist/src/broker/effect-upgrade.d.ts +3 -0
- package/dist/src/broker/effect-upgrade.js +11 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +43 -3
- package/dist/src/cli/chat-stores.d.ts +2 -0
- package/dist/src/cli/chat-stores.js +113 -0
- package/dist/src/cli/client.d.ts +7 -2
- package/dist/src/cli/client.js +13 -7
- package/dist/src/cli/command-requests.d.ts +46 -0
- package/dist/src/cli/command-requests.js +84 -0
- package/dist/src/cli/command-waits.d.ts +9 -0
- package/dist/src/cli/command-waits.js +51 -0
- package/dist/src/cli/commands.js +70 -88
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/config-notice.js +5 -2
- package/dist/src/cli/doctor-retention.d.ts +2 -0
- package/dist/src/cli/doctor-retention.js +93 -0
- package/dist/src/cli/doctor-workflows.d.ts +5 -2
- package/dist/src/cli/doctor-workflows.js +12 -7
- package/dist/src/cli/doctor.js +11 -9
- package/dist/src/cli/harness-probes.d.ts +2 -0
- package/dist/src/cli/harness-probes.js +1 -1
- package/dist/src/cli/harness-processes.d.ts +6 -0
- package/dist/src/cli/harness-processes.js +36 -0
- package/dist/src/cli/init-command.d.ts +9 -0
- package/dist/src/cli/init-command.js +52 -0
- package/dist/src/cli/init-prompt-command.d.ts +10 -0
- package/dist/src/cli/init-prompt-command.js +145 -0
- package/dist/src/cli/init-prompt.d.ts +35 -0
- package/dist/src/cli/init-prompt.js +74 -0
- package/dist/src/cli/init-selection.d.ts +13 -0
- package/dist/src/cli/init-selection.js +75 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +37 -7
- package/dist/src/cli/mcp-server.d.ts +1 -0
- package/dist/src/cli/mcp-server.js +156 -0
- package/dist/src/cli/mcp-tools.d.ts +15 -0
- package/dist/src/cli/mcp-tools.js +242 -0
- package/dist/src/cli/queue-arguments.d.ts +15 -0
- package/dist/src/cli/queue-arguments.js +31 -0
- package/dist/src/cli/queue-render.d.ts +3 -0
- package/dist/src/cli/queue-render.js +26 -0
- package/dist/src/cli/reload-render.d.ts +2 -0
- package/dist/src/cli/reload-render.js +12 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +54 -38
- package/dist/src/cli/report-ci-jobs.d.ts +23 -0
- package/dist/src/cli/report-ci-jobs.js +103 -0
- package/dist/src/cli/report-ci-usage.d.ts +9 -0
- package/dist/src/cli/report-ci-usage.js +185 -0
- package/dist/src/cli/report-ci.d.ts +13 -0
- package/dist/src/cli/report-ci.js +74 -0
- package/dist/src/cli/report-closures.d.ts +6 -0
- package/dist/src/cli/report-closures.js +97 -0
- package/dist/src/cli/report-flow.d.ts +7 -0
- package/dist/src/cli/report-flow.js +122 -0
- package/dist/src/cli/report-github-reader.d.ts +29 -0
- package/dist/src/cli/report-github-reader.js +157 -0
- package/dist/src/cli/report-github.d.ts +15 -8
- package/dist/src/cli/report-github.js +131 -150
- package/dist/src/cli/report-operator.d.ts +3 -0
- package/dist/src/cli/report-operator.js +40 -0
- package/dist/src/cli/report-ready.d.ts +3 -0
- package/dist/src/cli/report-ready.js +96 -0
- package/dist/src/cli/report-text.d.ts +9 -0
- package/dist/src/cli/report-text.js +33 -0
- package/dist/src/cli/report.d.ts +1 -0
- package/dist/src/cli/report.js +104 -27
- package/dist/src/cli/runtime-arguments.d.ts +18 -3
- package/dist/src/cli/runtime-arguments.js +29 -20
- package/dist/src/cli/schedule-arguments.d.ts +14 -0
- package/dist/src/cli/schedule-arguments.js +26 -0
- package/dist/src/cli/schedule-render.d.ts +22 -0
- package/dist/src/cli/schedule-render.js +73 -0
- package/dist/src/cli/terminal-text.d.ts +3 -0
- package/dist/src/cli/terminal-text.js +28 -0
- package/dist/src/cli/toolchain.d.ts +1 -0
- package/dist/src/cli/toolchain.js +1 -0
- package/dist/src/cli/usage-render.d.ts +1 -0
- package/dist/src/cli/usage-render.js +28 -1
- package/dist/src/cli/usage.d.ts +2 -2
- package/dist/src/cli/usage.js +89 -11
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-api-document.d.ts +430 -0
- package/dist/src/cli/watch-api-document.js +291 -0
- package/dist/src/cli/watch-api-run.d.ts +56 -0
- package/dist/src/cli/watch-api-run.js +112 -0
- package/dist/src/cli/watch-api.d.ts +17 -0
- package/dist/src/cli/watch-api.js +230 -0
- package/dist/src/cli/watch-board-view.js +19 -2
- package/dist/src/cli/watch-board.d.ts +4 -2
- package/dist/src/cli/watch-board.js +53 -43
- package/dist/src/cli/watch-card-forms.d.ts +1 -1
- package/dist/src/cli/watch-card-forms.js +11 -10
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +2 -11
- package/dist/src/cli/watch-header-view.d.ts +1 -5
- package/dist/src/cli/watch-header-view.js +17 -21
- package/dist/src/cli/watch-model.d.ts +5 -1
- package/dist/src/cli/watch-model.js +20 -11
- package/dist/src/cli/watch-page.js +15 -15
- package/dist/src/cli/watch-phases.d.ts +12 -3
- package/dist/src/cli/watch-phases.js +68 -11
- package/dist/src/cli/watch-pr-board.js +1 -1
- package/dist/src/cli/watch-pr-command.d.ts +1 -0
- package/dist/src/cli/watch-pull-request.js +18 -8
- package/dist/src/cli/watch-reads.d.ts +3 -0
- package/dist/src/cli/watch-reads.js +22 -20
- package/dist/src/cli/watch-render.d.ts +15 -0
- package/dist/src/cli/watch-run-input.d.ts +0 -1
- package/dist/src/cli/watch-run-input.js +0 -13
- package/dist/src/cli/watch-server.js +24 -10
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +73 -12
- package/dist/src/command-wait.d.ts +4 -0
- package/dist/src/command-wait.js +45 -0
- package/dist/src/configuration-change.d.ts +7 -0
- package/dist/src/configuration-change.js +14 -0
- package/dist/src/configuration-display.js +2 -0
- package/dist/src/configuration-schema.d.ts +14 -0
- package/dist/src/configuration-schema.js +6 -2
- package/dist/src/daemon/attachment-file.d.ts +6 -0
- package/dist/src/daemon/attachment-file.js +86 -0
- package/dist/src/daemon/attachments.d.ts +14 -0
- package/dist/src/daemon/attachments.js +17 -0
- package/dist/src/daemon/claude-recovery.d.ts +50 -0
- package/dist/src/daemon/claude-recovery.js +208 -0
- package/dist/src/daemon/claude-stream.d.ts +27 -0
- package/dist/src/daemon/claude-stream.js +63 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -25
- package/dist/src/daemon/claude-turn.js +64 -81
- package/dist/src/daemon/claude-worker.d.ts +5 -4
- package/dist/src/daemon/claude-worker.js +127 -126
- package/dist/src/daemon/daemon-adapters.d.ts +9 -0
- package/dist/src/daemon/daemon-adapters.js +33 -5
- package/dist/src/daemon/daemon-loops.d.ts +5 -1
- package/dist/src/daemon/daemon-loops.js +18 -10
- package/dist/src/daemon/daemon.js +80 -61
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +222 -0
- package/dist/src/daemon/github-calls.js +1 -1
- package/dist/src/daemon/github-ci-filters.d.ts +6 -0
- package/dist/src/daemon/github-ci-filters.js +138 -0
- package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
- package/dist/src/daemon/github-ci-workflows.js +148 -0
- package/dist/src/daemon/github-ci.js +22 -4
- package/dist/src/daemon/github-issue-methods.d.ts +2 -0
- package/dist/src/daemon/github-issue-methods.js +37 -2
- package/dist/src/daemon/github-merge-call.d.ts +2 -1
- package/dist/src/daemon/github-merge-call.js +10 -3
- package/dist/src/daemon/github-merge.js +52 -24
- package/dist/src/daemon/github-methods.js +18 -4
- package/dist/src/daemon/github-operation.d.ts +4 -0
- package/dist/src/daemon/github-operation.js +6 -0
- package/dist/src/daemon/github-worker.d.ts +4 -0
- package/dist/src/daemon/github-worker.js +6 -0
- package/dist/src/daemon/issue-queue.d.ts +4 -1
- package/dist/src/daemon/issue-queue.js +76 -78
- package/dist/src/daemon/merge-turns.d.ts +10 -0
- package/dist/src/daemon/merge-turns.js +37 -0
- package/dist/src/daemon/notify-events.d.ts +6 -0
- package/dist/src/daemon/notify-events.js +84 -0
- package/dist/src/daemon/notify-journal.js +1 -1
- package/dist/src/daemon/notify-message.d.ts +4 -1
- package/dist/src/daemon/notify-message.js +36 -0
- package/dist/src/daemon/notify.d.ts +1 -1
- package/dist/src/daemon/notify.js +5 -77
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/queue-control.d.ts +13 -0
- package/dist/src/daemon/queue-control.js +86 -0
- package/dist/src/daemon/queue-journal.d.ts +20 -0
- package/dist/src/daemon/queue-journal.js +89 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/record-archive.d.ts +19 -0
- package/dist/src/daemon/record-archive.js +82 -0
- package/dist/src/daemon/record-sweep.d.ts +24 -0
- package/dist/src/daemon/record-sweep.js +147 -0
- package/dist/src/daemon/resume-index-lock.d.ts +13 -0
- package/dist/src/daemon/resume-index-lock.js +160 -0
- package/dist/src/daemon/resume-worktree.d.ts +7 -0
- package/dist/src/daemon/resume-worktree.js +29 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -12
- package/dist/src/daemon/retrying-turn.js +98 -172
- package/dist/src/daemon/schedule-control.d.ts +26 -0
- package/dist/src/daemon/schedule-control.js +110 -0
- package/dist/src/daemon/schedule-journal.d.ts +2 -15
- package/dist/src/daemon/schedule-journal.js +67 -4
- package/dist/src/daemon/settings-reload.d.ts +26 -0
- package/dist/src/daemon/settings-reload.js +82 -0
- package/dist/src/daemon/ticket-registration.d.ts +2 -7
- package/dist/src/daemon/ticket-registration.js +15 -81
- package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
- package/dist/src/daemon/turn-attempt-journal.js +136 -0
- package/dist/src/daemon/turn-attempts.d.ts +47 -0
- package/dist/src/daemon/turn-attempts.js +166 -0
- package/dist/src/daemon/turn-details.d.ts +4 -0
- package/dist/src/daemon/turn-details.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +8 -1
- package/dist/src/daemon/turn-report.js +39 -0
- package/dist/src/daemon/work-tree.d.ts +9 -0
- package/dist/src/daemon/work-tree.js +20 -0
- package/dist/src/daemon/worker-profile.d.ts +9 -0
- package/dist/src/daemon/worker-profile.js +44 -0
- package/dist/src/daemon/workflow-generations.d.ts +7 -4
- package/dist/src/daemon/workflow-generations.js +22 -14
- package/dist/src/daemon/workflow-reload.d.ts +41 -0
- package/dist/src/daemon/workflow-reload.js +244 -0
- package/dist/src/daemon/workflow-replay.d.ts +2 -1
- package/dist/src/daemon/workflow-replay.js +7 -3
- package/dist/src/daemon/workflow-schedules.d.ts +3 -0
- package/dist/src/daemon/workflow-schedules.js +98 -45
- package/dist/src/daemon/worktree-processes.d.ts +9 -0
- package/dist/src/daemon/worktree-processes.js +151 -0
- package/dist/src/doctor-report.d.ts +4 -6
- package/dist/src/doctor-report.js +8 -13
- package/dist/src/harness-start.d.ts +15 -0
- package/dist/src/harness-start.js +37 -0
- package/dist/src/host/command-wait.d.ts +38 -0
- package/dist/src/host/command-wait.js +115 -0
- package/dist/src/host/start-delivery.d.ts +5 -7
- package/dist/src/host/start-delivery.js +3 -15
- package/dist/src/host/step-bridge-host.d.ts +2 -0
- package/dist/src/host/step-bridge-host.js +21 -0
- package/dist/src/operation-identity.d.ts +1 -0
- package/dist/src/operation-identity.js +4 -0
- package/dist/src/private-config.schema.json +71 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +16 -2
- package/dist/src/project-settings.js +35 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/queue-state.d.ts +26 -0
- package/dist/src/queue-state.js +34 -0
- package/dist/src/record-retention.d.ts +46 -0
- package/dist/src/record-retention.js +81 -0
- package/dist/src/relay/relay-service.d.ts +3 -0
- package/dist/src/relay/relay-service.js +5 -3
- package/dist/src/report-ci.d.ts +164 -0
- package/dist/src/report-ci.js +32 -0
- package/dist/src/report-effects.d.ts +15 -0
- package/dist/src/report-effects.js +212 -0
- package/dist/src/report-flow-types.d.ts +38 -0
- package/dist/src/report-flow-types.js +7 -0
- package/dist/src/report-flow.d.ts +43 -0
- package/dist/src/report-flow.js +193 -0
- package/dist/src/report-operator.d.ts +67 -0
- package/dist/src/report-operator.js +25 -0
- package/dist/src/report-quality.d.ts +221 -0
- package/dist/src/report-quality.js +94 -0
- package/dist/src/report-ready.d.ts +23 -0
- package/dist/src/report-ready.js +117 -0
- package/dist/src/report-statistics.d.ts +2 -1
- package/dist/src/report-statistics.js +40 -4
- package/dist/src/report.d.ts +588 -47
- package/dist/src/report.js +156 -41
- package/dist/src/schedule-progress.d.ts +33 -0
- package/dist/src/schedule-progress.js +45 -0
- package/dist/src/service/active-tickets.js +11 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/dispatcher.d.ts +4 -0
- package/dist/src/service/dispatcher.js +33 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-handlers.d.ts +4 -0
- package/dist/src/service/queue-handlers.js +32 -0
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/registry.d.ts +28 -2
- package/dist/src/service/registry.js +48 -0
- package/dist/src/service/replies.d.ts +22 -8
- package/dist/src/service/replies.js +16 -2
- package/dist/src/service/run-handlers.js +37 -12
- package/dist/src/service/run-metadata.d.ts +15 -1
- package/dist/src/service/run-metadata.js +93 -8
- package/dist/src/service/service.d.ts +11 -3
- package/dist/src/service/service.js +22 -37
- package/dist/src/service/submission-handler.js +18 -4
- package/dist/src/service/worker-port.js +9 -1
- package/dist/src/service/worker-totals.d.ts +6 -0
- package/dist/src/service/worker-totals.js +8 -1
- package/dist/src/service/workflow-reload.d.ts +35 -0
- package/dist/src/service/workflow-reload.js +52 -0
- package/dist/src/step-bridge.d.ts +20 -0
- package/dist/src/steps/command-wait.d.ts +12 -0
- package/dist/src/steps/command-wait.js +26 -0
- package/dist/src/steps/open-decision-wait.d.ts +2 -0
- package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
- package/dist/src/steps/review-by-person.js +4 -1
- package/dist/src/steps/wait-for-command.d.ts +3 -0
- package/dist/src/steps/wait-for-command.js +17 -0
- package/dist/src/steps/wait-for-decision.js +1 -1
- package/dist/src/storage/command-wait-rows.d.ts +30 -0
- package/dist/src/storage/command-wait-rows.js +96 -0
- package/dist/src/storage/decision-snapshots.d.ts +8 -2
- package/dist/src/storage/decision-snapshots.js +16 -8
- package/dist/src/storage/domain-changes.d.ts +3 -1
- package/dist/src/storage/domain-changes.js +4 -0
- package/dist/src/storage/domain-schema.d.ts +16 -1
- package/dist/src/storage/domain-schema.js +35 -4
- package/dist/src/storage/effect-schema.d.ts +2 -0
- package/dist/src/storage/effect-schema.js +9 -0
- package/dist/src/storage/projection-changes.d.ts +12 -0
- package/dist/src/storage/projection-changes.js +194 -0
- package/dist/src/storage/projection-lookups.d.ts +7 -0
- package/dist/src/storage/projection-lookups.js +30 -0
- package/dist/src/testing-requests.d.ts +15 -0
- package/dist/src/testing-requests.js +93 -0
- package/dist/src/testing.d.ts +4 -10
- package/dist/src/testing.js +33 -86
- package/dist/src/worker-usage.d.ts +1 -0
- package/dist/src/worker-usage.js +3 -0
- package/dist/src/workflow-candidate.d.ts +1 -0
- package/dist/src/workflow-candidate.js +12 -1
- package/dist/src/workflow-contracts.d.ts +1 -0
- package/dist/src/workflow-contracts.js +9 -2
- package/dist/src/workflow-declaration.d.ts +1 -0
- package/dist/src/workflow-declaration.js +3 -0
- package/dist/src/workflow-discovery.d.ts +2 -13
- package/dist/src/workflow-discovery.js +1 -13
- package/dist/src/workflow-refusals.js +0 -1
- package/dist/src/workflows.d.ts +1 -1
- package/dist/src/workflows.js +1 -1
- package/dist/tools/compile-workflows.js +3 -0
- package/dist/tools/project-configuration.d.ts +7 -2
- package/dist/tools/project-configuration.js +30 -1
- package/dist/tools/red-green-command.d.ts +1 -0
- package/dist/tools/red-green-command.js +174 -0
- package/dist/tools/red-green-process.d.ts +10 -0
- package/dist/tools/red-green-process.js +59 -0
- package/dist/tools/self-host-processes.d.ts +2 -0
- package/dist/tools/self-host-processes.js +69 -26
- package/dist/tools/self-host-project.d.ts +2 -0
- package/dist/tools/self-host-project.js +30 -77
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +76 -34
- package/dist/tools/template-command.d.ts +1 -0
- package/dist/tools/template-command.js +160 -0
- package/dist/tools/template-copy.d.ts +11 -0
- package/dist/tools/template-copy.js +130 -0
- package/dist/tools/template-files.d.ts +17 -0
- package/dist/tools/template-files.js +74 -0
- package/dist/tools/workflow-bundles.js +1 -0
- package/dist/tools/workflow-candidate-counts.js +2 -2
- package/dist/tools/workflow-candidate-program.d.ts +4 -2
- package/dist/tools/workflow-candidate-program.js +30 -11
- package/dist/tools/workflow-candidate-shape.d.ts +3 -0
- package/dist/tools/workflow-candidate-shape.js +90 -0
- package/dist/tools/workflow-candidate-source.d.ts +1 -0
- package/dist/tools/workflow-candidate-source.js +26 -4
- package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
- package/dist/tools/workflow-candidate-syntax.js +24 -94
- package/dist/tools/workflow-command.js +1 -2
- package/dist/tools/workflow-folders.d.ts +2 -3
- package/dist/tools/workflow-folders.js +1 -1
- package/package.json +17 -9
- package/templates/develop/README.md +93 -4
- package/templates/develop/develop/flow-tests.ts +38 -1
- package/templates/develop/develop/interruption-tests.ts +157 -0
- package/templates/develop/develop/local.ts +1 -0
- package/templates/develop/develop/option-tests.ts +138 -9
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/red-green.ts +55 -0
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/report.ts +31 -11
- package/templates/develop/develop/round.ts +1 -0
- package/templates/develop/develop/scenarios.ts +27 -0
- package/templates/develop/develop/turn.ts +28 -7
- package/templates/develop/develop.declaration.json +1 -1
- package/templates/develop/develop.test.ts +4 -0
- package/templates/develop/template.json +29 -2
- package/templates/idea-to-issue/README.md +27 -0
- package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
- package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
- package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
- package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
- package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
- package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
- package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
- package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
- package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
- package/templates/idea-to-issue/idea-to-issue.ts +49 -0
- package/templates/idea-to-issue/template.json +81 -0
- package/templates/review-day/README.md +97 -0
- package/templates/review-day/review-day/critique.ts +58 -0
- package/templates/review-day/review-day/decision.ts +29 -0
- package/templates/review-day/review-day/facts.ts +69 -0
- package/templates/review-day/review-day/label.ts +29 -0
- package/templates/review-day/review-day/next.ts +28 -0
- package/templates/review-day/review-day/post.ts +27 -0
- package/templates/review-day/review-day/report.ts +98 -0
- package/templates/review-day/review-day/rules.ts +12 -0
- package/templates/review-day/review-day/scenarios.ts +76 -0
- package/templates/review-day/review-day/turn.ts +73 -0
- package/templates/review-day/review-day.declaration.json +16 -0
- package/templates/review-day/review-day.test.ts +362 -0
- package/templates/review-day/review-day.ts +37 -0
- package/templates/review-day/template.json +56 -0
- package/dist/src/cli/watch-start-view.d.ts +0 -18
- package/dist/src/cli/watch-start-view.js +0 -77
- package/dist/src/steps/decision-gate.d.ts +0 -3
- package/dist/workflows/develop-prd.d.ts +0 -7
- package/dist/workflows/develop-prd.js +0 -165
- package/dist/workflows/develop-ticket.d.ts +0 -9
- package/dist/workflows/develop-ticket.js +0 -207
- package/dist/workflows/issue-labels.d.ts +0 -16
- package/dist/workflows/issue-labels.js +0 -70
- package/dist/workflows/ticket-prompts.d.ts +0 -35
- package/dist/workflows/ticket-prompts.js +0 -147
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Build a software factory with simple TypeScript for your project, and your proje
|
|
|
6
6
|
|
|
7
7
|
The end of vibe coding. This is agentic engineering.
|
|
8
8
|
|
|
9
|
-
A workflow file in TypeScript is the factory. It sets the steps: a worker turn in a work tree, a pull request, a review and a merge. Cloving keeps the state of each run and a record of each step. A GitHub step continues after a restart of the service. A worker turn in work stops at a restart. Cloving builds itself through `develop
|
|
9
|
+
A workflow file in TypeScript is the factory. It sets the steps: a worker turn in a work tree, a pull request, a review and a merge. Cloving keeps the state of each run and a record of each step. A GitHub step continues after a restart of the service. A worker turn in work stops at a restart. Cloving builds itself through a private copy of the `develop` template for this repository.
|
|
10
10
|
|
|
11
11
|
## Cloving
|
|
12
12
|
|
|
@@ -17,18 +17,18 @@ This pre-release has one supervised slice: a service for one git repository, a w
|
|
|
17
17
|
What works now:
|
|
18
18
|
|
|
19
19
|
- `cloving start` starts the service for one git repository, with the workflow host, the Claude worker and a watch page.
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- Cloving develops itself through `develop-issue`, with a Greptile review and an automatic merge.
|
|
20
|
+
- `cloving start` registers workflows from repository `.cloving/workflows/` and user `cloving/workflows/` folders (see "Develop a workflow").
|
|
21
|
+
- The `develop` template supports ticket or task-text input and human or automatic review.
|
|
22
|
+
- The default `develop` template uses Greptile review and merges at the confidence score 5/5, with no human approval.
|
|
23
|
+
- Cloving develops itself through `develop`, a private copy of the develop template, with a Greptile review and an automatic merge.
|
|
25
24
|
- The watch page shows the runs, the events and the work of the worker as it occurs.
|
|
26
25
|
|
|
26
|
+
- `cloving init-prompt` lists local chat-store metadata without reading chat contents. Its setup instructions ask for consent before the agent counts repeated work and samples chats to suggest linked workflows.
|
|
27
|
+
|
|
27
28
|
What does not work yet:
|
|
28
29
|
|
|
29
30
|
- The Claude worker is not confined. It runs as the current user.
|
|
30
31
|
- An approval does not merge the branch. You merge the branch yourself.
|
|
31
|
-
- Cloving cannot make a workflow from your earlier chats yet. The issues [#42](https://github.com/cloving-ai/cloving-ai/issues/42), [#43](https://github.com/cloving-ai/cloving-ai/issues/43) and [#44](https://github.com/cloving-ai/cloving-ai/issues/44) are open for this work. Until then, the prompt "Find workflows in your chats" is a guide for a coding agent.
|
|
32
32
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ A run needs these tools:
|
|
|
38
38
|
|
|
39
39
|
- `git`.
|
|
40
40
|
- The `claude` command of Claude Code on the search path. The Claude worker runs it as the current user.
|
|
41
|
-
- For
|
|
41
|
+
- For workflows that use GitHub: the `gh` command with a login. Workflows that select Greptile review also need Greptile on the repository. The worker uses the `gh` login and the git credentials of the current user.
|
|
42
42
|
|
|
43
43
|
Install the executable from npm:
|
|
44
44
|
|
|
@@ -47,7 +47,7 @@ npm install --global cloving --ignore-scripts
|
|
|
47
47
|
cloving --version
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
This package replaces the older Cloving CLI under the same npm name. The installed package includes startup, the watch command,
|
|
50
|
+
This package replaces the older Cloving CLI under the same npm name. The installed package includes startup, the watch command, workflow templates and the SDK compiler integration. It starts without a source checkout or development dependencies, using the installed runtime dependencies. Installation runs no scripts and starts no service.
|
|
51
51
|
|
|
52
52
|
For checkout development, get the code and install the dependencies:
|
|
53
53
|
|
|
@@ -90,7 +90,7 @@ npm install --ignore-scripts --omit=dev /path/to/TARBALL
|
|
|
90
90
|
./node_modules/.bin/cloving start
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
The installed executable includes JavaScript for startup, the watch command and
|
|
93
|
+
The installed executable includes JavaScript for startup, the watch command and workflow support. It uses the installed runtime dependencies, including the SDK compiler, without a source checkout. Runtime state and generated workflow artifacts use the configured runtime location outside the installation. Installation scripts are unnecessary. The checkout launcher above remains supported, including its existing checkout self-update behavior; installing a tarball does not add package self-updates.
|
|
94
94
|
|
|
95
95
|
For a project-local tarball installation, use `./node_modules/.bin/cloving` wherever the examples below say `cloving`, or add your project's `node_modules/.bin` to the search path. After a build, `npm link` also supplies the executable.
|
|
96
96
|
|
|
@@ -100,7 +100,7 @@ For a project-local tarball installation, use `./node_modules/.bin/cloving` wher
|
|
|
100
100
|
|
|
101
101
|
Each file requires `"version": 1`. Environment settings override private settings, which override project settings, which override built-in defaults. The start guide names each configured field's source: `environment`, `private` or `project`.
|
|
102
102
|
|
|
103
|
-
The project file supports `checks.beforeMerge`, `checks.required`, `tickets.command`, `tickets.nextCommand`, `queue.everySeconds` and `queue.
|
|
103
|
+
The project file supports `checks.beforeMerge`, `checks.required`, `checks.redGreen`, `tickets.command`, `tickets.nextCommand`, `queue.everySeconds`, `queue.lanes` and `queue.dailySpendLimitUsd`. The private file supports these same fields plus `harness.name`, `harness.kind`, `harness.path`, `harness.command`, `harness.turn`, `harness.output`, `profiles`, `fallbackModels`, `tokenPrices`, `privateTexts`, `notify.command`, `watch.port`, `watch.actions`, `selfUpdate.everySeconds`, `github.command`, `workflows.folder`, `retention.days`, `retention.action` and `retention.archiveFolder`. Commands are arrays of arguments; seconds, lanes, spend limits and ports are numbers. A watch port can also be `"off"`; watch actions are `"on"` or `"off"`. The retention days are a whole number of at least 1, or `null` to keep all records; the default is 30. The retention action is `"archive"` or `"delete"`; the default is `"archive"`. The archive folder is an absolute path, or `null` for the `archive` folder in the state folder.
|
|
104
104
|
|
|
105
105
|
For example, a shared `.cloving/config.json` can contain:
|
|
106
106
|
|
|
@@ -126,69 +126,29 @@ cloving config unset queue.lanes --private
|
|
|
126
126
|
|
|
127
127
|
All four commands accept `--json` and `--repository <directory>`. Use the setting names listed above; `profiles` and `tokenPrices` are whole JSON maps, and dictionary subpaths are unknown settings. Values are parsed as JSON, falling back to text. Changes are validated before writing and go to the field's default file; `--private` writes an override in the private file. `list` and `get` show each value's source, including `default`, and all hidden file values. JSON results have `schemaVersion: 1`; list returns a `settings` array, get returns `field`, `value`, `source` and `hidden`. A default `null` means no configured value. Mutation results include `field`, `scope`, `action` and `notice`; notice is null when no service is running.
|
|
128
128
|
|
|
129
|
-
Each change holds a file lock from read through atomic replacement, keeping the previous bytes as `<file>.bak`. A first write needs no backup. Private files, backups and temporary files have mode 0600. Locks from stopped processes are reclaimed; a live lock waits at most ten seconds, then exits with `settings-locked`. Invalid settings and unknown fields exit with status 2 without changing a file. For a running service, the result explains whether to restart to use the new value or whether an environment or private source will keep hiding it after a restart. Settings do not reload automatically.
|
|
129
|
+
Each change holds a file lock from read through atomic replacement, keeping the previous bytes as `<file>.bak`. A first write needs no backup. Private files, backups and temporary files have mode 0600. Locks from stopped processes are reclaimed; a live lock waits at most ten seconds, then exits with `settings-locked`. Invalid settings and unknown fields exit with status 2 without changing a file. For a running service, the result explains whether to run `cloving reload` or to restart to use the new value, or whether an environment or private source will keep hiding it after a restart. Settings do not reload automatically.
|
|
130
130
|
|
|
131
131
|
Changing or unsetting `harness.name` clears kind, path and command. Changing or unsetting kind clears path and command; changing or unsetting path clears command. This keeps the previous harness's configuration from carrying into a new selection.
|
|
132
132
|
|
|
133
133
|
The package includes [the project schema](src/project-config.schema.json) and [the private schema](src/private-config.schema.json), also installed under `dist/src/`. Unknown fields fail with `unknown-setting: <field>`, invalid values with `invalid-setting: <field>`, and unsupported or missing versions with `unsupported-config-version: version`. Private fields in the project file fail with `private-setting-in-project-file: <field>`. Files cannot set runtime directories, ownership leases, host bounds or the watch repository; those remain environment settings.
|
|
134
134
|
|
|
135
|
-
Run `cloving doctor` from the repository before starting the service. It lists each requirement with a fixed code, `ok`, `fail` or `skip`, and a fixing command. Required failures and skipped prerequisites exit with status 1. `cloving doctor --json` prints the same checks as `{ "version": 1, "checks": [...] }` for setup agents.
|
|
136
|
-
|
|
137
|
-
Doctor probes harness versions and effective executable paths without running a turn. Shell scripts and simple `node script` wrappers receive `--version` from the repository folder; unsupported launcher arguments fail the probe. GitHub login and reads use the origin's host, including GitHub Enterprise. GitHub calls are reads limited to ten seconds each; a service probe waits at most five seconds. Recent Greptile activity does not establish that a usable review is available, and missing activity does not prove the app is absent.
|
|
138
|
-
|
|
139
|
-
## First run
|
|
140
|
-
|
|
141
|
-
This first run uses `develop-prompt` on a test repository. It needs no ticket command and no GitHub repository.
|
|
142
|
-
|
|
143
|
-
1. Make a test repository with one commit:
|
|
144
|
-
|
|
145
|
-
```sh
|
|
146
|
-
mkdir ~/cloving-trial
|
|
147
|
-
cd ~/cloving-trial
|
|
148
|
-
git init
|
|
149
|
-
echo "A test project." > README.md
|
|
150
|
-
git add README.md
|
|
151
|
-
git commit -m "Start the test project"
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
2. In terminal 1, in the test repository, start the service. Keep this terminal open:
|
|
155
|
-
|
|
156
|
-
```sh
|
|
157
|
-
cloving start
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
`cloving start` copies the workflow file into a host project, compiles it there, and starts the service. Then it prints the commands for a second terminal.
|
|
161
|
-
|
|
162
|
-
3. Open the watch page on `http://127.0.0.1:3663/`.
|
|
163
|
-
|
|
164
|
-
4. In terminal 2, submit a run:
|
|
165
|
-
|
|
166
|
-
```sh
|
|
167
|
-
cloving run develop-prompt --prompt "Add a file HELLO.md with one line of text."
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
The command prints a committed receipt with the run ID. A receipt does not mean completed work.
|
|
135
|
+
Run `cloving doctor` from the repository before starting the service. It lists each requirement with a fixed code, `ok`, `warn`, `fail` or `skip`, and a fixing command. Required failures and skipped prerequisites exit with status 1. A warning does not change the exit status. `cloving doctor --json` prints the same checks as `{ "version": 1, "checks": [...] }` for setup agents.
|
|
171
136
|
|
|
172
|
-
|
|
137
|
+
The required `no-workflow` check fails when neither the project nor the user folder has a workflow declaration. Its fix is `cloving init`. During `cloving init-prompt` setup, defer this check to the template step, copy or create the workflow, then run doctor again. `no-workflow` must report `ok` before setup is ready.
|
|
173
138
|
|
|
174
|
-
|
|
175
|
-
cloving questions
|
|
176
|
-
```
|
|
139
|
+
The optional `retention` check shows the size and the folder count of `journal/` and `github/` in the state folder, the age of the oldest kept record folder, and the values of `retention.days`, `retention.action` and `retention.archiveFolder`. The size includes all files in the two folders. The folder count and the age include only the record folders that the retention rule can archive or delete. The age of a folder starts at the change time of its newest file. The check gives `warn` when `retention.days` is `null` and the records are larger than 1 GB (1,000,000,000 bytes). An invalid retention setting fails the check and names the variable.
|
|
177
140
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
6. Read the diff before you decide. In the test repository, `git diff HEAD...BRANCH` shows the work of the branch.
|
|
141
|
+
Doctor probes harness versions and effective executable paths without running a turn. Shell scripts and simple `node script` wrappers receive `--version` from the repository folder; unsupported launcher arguments fail the probe. GitHub login and reads use the origin's host, including GitHub Enterprise. GitHub calls are reads limited to ten seconds each; a service probe waits at most five seconds. Recent Greptile activity does not establish that a usable review is available, and missing activity does not prove the app is absent.
|
|
181
142
|
|
|
182
|
-
|
|
143
|
+
## First run
|
|
183
144
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
```
|
|
145
|
+
```sh
|
|
146
|
+
cloving init
|
|
147
|
+
```
|
|
188
148
|
|
|
189
|
-
|
|
149
|
+
Run this in your git repository. Choose the agent harness for setup; Cloving saves it in your private repository settings and opens the agent with ``run `cloving init-prompt` `` as its first message. The agent walks through setup, a first run and a first ticket with you.
|
|
190
150
|
|
|
191
|
-
|
|
151
|
+
Use `cloving init --harness <name or path>` to skip the question. A name with both a file and a shell entry needs an explicit path or `--harness shell:<name>`. A later `cloving init` lists your current default first. The harness stays attached to your terminal, uses its normal permissions and returns its exit status when the session ends.
|
|
192
152
|
|
|
193
153
|
### The service and its settings
|
|
194
154
|
|
|
@@ -200,25 +160,25 @@ On start, Cloving keeps the old default runtime path only when all retained work
|
|
|
200
160
|
|
|
201
161
|
`cloving watch` serves a local page on `http://127.0.0.1:3663/` (`--port` selects a different port). The page shows the runs, the events, the work of the worker as it occurs, and each pending decision with its approve and deny commands. `cloving start` starts the page too; `CLOVING_WATCH_PORT` selects its port, and the value `off` starts none.
|
|
202
162
|
|
|
203
|
-
Each workflow board with supported inputs has **+ Add a card** at the bottom of its first column, including an empty board.
|
|
163
|
+
Each workflow board with supported inputs has **+ Add a card** at the bottom of its first column, including an empty board. The form uses the string and ticket fields of the workflow's registered declaration. Ticket fields are labeled **Ticket ID**; other fields use their declared names, and optional fields can be left out. Unsupported inputs have no control. Select **Add card** or press Enter in a field to send. **Cancel** and Esc close the form. The service reply shows the admitted run ID or a refusal code; admitted cards arrive through the existing live stream.
|
|
204
164
|
|
|
205
|
-
The form sends the same run request as the CLI and retains its random command ID for retries, including a lost reply. Retry the same form to avoid duplicate runs. The write endpoint accepts at most 16 KiB of JSON, requires the page's random token, matching Origin and a loopback/localhost Host with the bound port, and allows no cross-origin preflight. `CLOVING_WATCH_ACTIONS=off` removes both the form control and the endpoint; actions are enabled by default.
|
|
165
|
+
The form sends the same run request as the CLI and retains its random command ID for retries, including a lost reply. Retry the same form to avoid duplicate runs. The write endpoint accepts at most 16 KiB of JSON, requires the page's random token, matching Origin and a loopback/localhost Host with the bound port, and allows no cross-origin preflight. `CLOVING_WATCH_ACTIONS=off` removes both the form control and the endpoint; actions are enabled by default. Decisions and other run actions still use their displayed CLI commands.
|
|
206
166
|
|
|
207
167
|
`cloving start` reads its settings from the environment. `cloving start --help` gives the form and the default of each setting:
|
|
208
168
|
|
|
209
169
|
- `CLOVING_RUNTIME_DIR`: the runtime directory.
|
|
210
170
|
- `CLOVING_TICKET_COMMAND`: the ticket command (see "Daily development").
|
|
211
|
-
- `CLOVING_NOTIFY_COMMAND`: a JSON list naming a command to notify the operator about pending decisions, blocked runs and
|
|
171
|
+
- `CLOVING_NOTIFY_COMMAND`: a JSON list naming a command to notify the operator about pending decisions, blocked runs, failed runs and stopped schedules. It has no default.
|
|
212
172
|
- `CLOVING_NEXT_COMMAND`: a JSON list of a command and its arguments that prints the next ready ticket ID for `--next`. It has no default.
|
|
213
173
|
- `CLOVING_CLAUDE_COMMAND`: a replacement of the `claude` command of the worker.
|
|
214
|
-
- `CLOVING_PROFILES`: a JSON file of named turn profiles
|
|
174
|
+
- `CLOVING_PROFILES`: a JSON file of named turn profiles. The service reads it at the start and at each `cloving reload`.
|
|
215
175
|
- `CLOVING_COMMANDS`: a JSON object mapping command names to argument arrays, such as `{"review-requests":["/opt/cloving/scan-reviews.mjs"]}`. Names contain 1–64 ASCII letters, digits or hyphens; the first argument must be an absolute executable path. Unset means no commands. Invalid values stop startup with `invalid-commands`.
|
|
216
176
|
- `CLOVING_COMMAND_SECONDS`: a whole number from 1 to 3600, default 60. Invalid values stop startup with `invalid-command-seconds`. A command exceeding the deadline fails with `command-timeout`.
|
|
217
177
|
- `CLOVING_WATCH_ACTIONS`: `off` disables starting runs from the board; default `on`.
|
|
218
178
|
- `CLOVING_WATCH_PORT`: the port of the watch page, or `off`.
|
|
219
179
|
- `CLOVING_WATCH_REPOSITORY`: repository context for a separate watch process. `start` sets this from its service repository. The watch process uses its local origin and has no current-directory default.
|
|
220
180
|
- `CLOVING_OWNERSHIP_LEASE_SECONDS` and `CLOVING_HOST_BOUND`: limits of the workflow host.
|
|
221
|
-
- `CLOVING_GH_COMMAND`, `CLOVING_CHECK_COMMAND` and `CLOVING_PRIVATE_TEXTS`: settings of `develop
|
|
181
|
+
- `CLOVING_GH_COMMAND`, `CLOVING_CHECK_COMMAND` and `CLOVING_PRIVATE_TEXTS`: settings of `develop`; the GitHub command and private-text list also apply to `idea-to-issue`.
|
|
222
182
|
|
|
223
183
|
A command setting is a JSON list of texts, for example `CLOVING_CHECK_COMMAND='["npm", "test"]'`.
|
|
224
184
|
|
|
@@ -228,6 +188,63 @@ The private `notify-events.json` journal records a notification as `pending` bef
|
|
|
228
188
|
|
|
229
189
|
Journal updates use a temporary file and rename. Sent and exhausted failed delivery details expire after seven days; their keys remain to prevent later duplicate delivery. Unfinished deliveries remain until resolved. A crash after command success but before recording that success can repeat delivery. Decisions opened and closed between checks can be missed.
|
|
230
190
|
|
|
191
|
+
#### Read API of the watch page
|
|
192
|
+
|
|
193
|
+
The watch page has a read API at `http://127.0.0.1:3663/api/v1`. Its OpenAPI 3.1 document is at `http://127.0.0.1:3663/api/v1/openapi.json`. OpenAPI client generators can read the document and make a typed client. The API accepts only `GET` and needs no authentication. An error reply is `application/problem+json` with a `code` member, for example `not-found` or `invalid-query`.
|
|
194
|
+
|
|
195
|
+
- `GET /api/v1/` gives the version of the API and its endpoints.
|
|
196
|
+
- `GET /api/v1/openapi.json` gives the OpenAPI document.
|
|
197
|
+
- `GET /api/v1/service` tells if the Cloving service answers.
|
|
198
|
+
- `GET /api/v1/workflows` gives the workflows with their counts and card fields.
|
|
199
|
+
- `GET /api/v1/runs` gives one page of runs, newest first. The query parameters `workflowId`, `state`, `limit` (1 to 200, default 50) and `cursor` select the runs. The `nextCursor` of a page gives the next page.
|
|
200
|
+
- `GET /api/v1/runs/{runId}` gives one run with its phases, open decisions, reviews and agent turns.
|
|
201
|
+
- `GET /api/v1/runs/{runId}/events` gives the events of one run, the lowest sequence first. The query parameter `after` (default 0) gives only the events with a higher sequence.
|
|
202
|
+
- `GET /api/v1/stream` sends Server-Sent Events. Each message has the event `change` and the data `{"updatedAt":"<time>"}`. Read the runs again when a message arrives.
|
|
203
|
+
|
|
204
|
+
Replace `<run-id>` with the ID of a run of `develop`, for example from the run list:
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
curl http://127.0.0.1:3663/api/v1/
|
|
208
|
+
curl http://127.0.0.1:3663/api/v1/openapi.json
|
|
209
|
+
curl http://127.0.0.1:3663/api/v1/service
|
|
210
|
+
curl http://127.0.0.1:3663/api/v1/workflows
|
|
211
|
+
curl 'http://127.0.0.1:3663/api/v1/runs?workflowId=develop&state=waiting_gate&limit=20'
|
|
212
|
+
curl 'http://127.0.0.1:3663/api/v1/runs/<run-id>'
|
|
213
|
+
curl 'http://127.0.0.1:3663/api/v1/runs/<run-id>/events?after=40'
|
|
214
|
+
curl -N http://127.0.0.1:3663/api/v1/stream
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The run list has the active runs and the runs of the last 7 days. The run detail reads each run, also a run older than 7 days. The events endpoint gives no event payloads, and the API has no write endpoint.
|
|
218
|
+
|
|
219
|
+
### Use Cloving from an MCP client
|
|
220
|
+
|
|
221
|
+
`cloving mcp --repository <directory>` serves Cloving tools to an MCP client over standard input and output. The server connects to the service of that repository. Start the service with `cloving start` before the client calls a tool.
|
|
222
|
+
|
|
223
|
+
Register the server in Claude Code:
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
claude mcp add cloving -- cloving mcp --repository <directory>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Register the server in Codex with this table in `~/.codex/config.toml`:
|
|
230
|
+
|
|
231
|
+
```toml
|
|
232
|
+
[mcp_servers.cloving]
|
|
233
|
+
command = "cloving"
|
|
234
|
+
args = ["mcp", "--repository", "<directory>"]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The server has ten tools:
|
|
238
|
+
|
|
239
|
+
- `cloving_status`, `cloving_questions` and `cloving_events` read the runs, the pending decisions and the events, as `cloving status`, `cloving questions` and `cloving events` do.
|
|
240
|
+
- `cloving_run` submits a run, as `cloving run` does. Give exactly one source: `prompt`, `ticket` (a ticket ID or `next`) or `input` (a JSON object, not a file path).
|
|
241
|
+
- `cloving_answer`, `cloving_approve` and `cloving_deny` record a decision. Read `reference`, `expectedRevision`, `generation` and `subjectDigest` from `cloving_questions`.
|
|
242
|
+
- `cloving_pause`, `cloving_resume` and `cloving_drop` send a run command with the `expectedRevision` of the run.
|
|
243
|
+
|
|
244
|
+
Each of the seven tools that change state requires a `commandId`. The server never makes a command ID. After a lost reply (`outcome-unknown`), send the same request with the same `commandId` again. The service then gives the stored receipt, also when the first request came from the CLI. A tool gives the same JSON object as the CLI command with `--json`. A refusal of the service gives `isError: true`, and an argument that is not valid gives the JSON-RPC error `-32602`. A cancel of a tool call stops the wait for the reply, but it does not cancel a command that the service admitted.
|
|
245
|
+
|
|
246
|
+
A tool call cannot start the service and cannot select a different repository. The server binds to one repository when it starts.
|
|
247
|
+
|
|
231
248
|
### Answer decisions from a phone
|
|
232
249
|
|
|
233
250
|
Cloving can send its pending decisions to the Cloving app on your phone, and the phone can answer them. `cloving start` runs the phone relay as a child process. `CLOVING_PHONE_RELAY` with the value `off` starts no relay. `CLOVING_RELAY_ORIGIN` selects the relay server; the default is `https://cloving.ai`.
|
|
@@ -251,44 +268,82 @@ The questions of `analyze-chats` are private. Their full text goes only to your
|
|
|
251
268
|
|
|
252
269
|
Run `cloving report --since 24 --json` for a versioned JSON report, or omit `--json` for text. `--since` accepts whole hours from 1 to 168 and defaults to 24. The window includes its start and excludes its end; the command captures the end time once. It reads the daemon's committed events and individual run status through the control socket. Set `CLOVING_WATCH_REPOSITORY` to the service repository to enable GitHub reads; its local origin supplies the host, owner and repository. There is no current-directory fallback. `CLOVING_GH_COMMAND` selects the GitHub command as a JSON argument array, defaulting to `gh`.
|
|
253
270
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| JSON value
|
|
257
|
-
|
|
|
258
|
-
| `metrics.tickets.completed`
|
|
259
|
-
| `metrics.pullRequests.merged`
|
|
260
|
-
| `metrics.runs.completed`
|
|
261
|
-
| `metrics.runs.partial`
|
|
262
|
-
| `metrics.runs.blocked`
|
|
263
|
-
| `metrics.runs.failed`
|
|
264
|
-
| `metrics.runs.cancelled`
|
|
265
|
-
| `metrics.cost.medianRunUsd`
|
|
266
|
-
| `runCosts`
|
|
267
|
-
|
|
268
|
-
|
|
271
|
+
The implemented report values are:
|
|
272
|
+
|
|
273
|
+
| JSON value | Meaning |
|
|
274
|
+
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
275
|
+
| `metrics.tickets.completed` | Issue close events with reason `completed` in the window. Reopened issues retain their completed closes. Each completed close counts, including repeated closes. Pull requests and other close reasons are excluded. `semantics.tickets` is `closed-completed-in-window`. |
|
|
276
|
+
| `metrics.pullRequests.merged` | Pull requests with a GitHub merge timestamp in the window. Closed, unmerged pull requests are excluded. |
|
|
277
|
+
| `metrics.runs.completed` | Terminal `run.completed` events with no outcome or with `handoff_requested`, excluding partial ticket handoffs. |
|
|
278
|
+
| `metrics.runs.partial` | Handoffs explicitly marked with partial ticket status. |
|
|
279
|
+
| `metrics.runs.blocked` | Terminal `run.completed` events with the blocked outcome. |
|
|
280
|
+
| `metrics.runs.failed` | Terminal `run.failed` events. |
|
|
281
|
+
| `metrics.runs.cancelled` | Terminal `run.cancelled` events. |
|
|
282
|
+
| `metrics.cost.medianRunUsd` | Median lifetime actual turn cost among runs ending in the window. Any unknown run cost makes this value unavailable. |
|
|
283
|
+
| `runCosts` | Each ended run's outcome, end time, actual total USD cost, individual turn operation IDs and actual prices, plus the historical daily median run-cost baseline. All of a run's turn cost is attributed to its end time, including turns before the window. Estimates never replace unknown actual prices. An observed run with no worker turns and settled effects has cost zero. A cancelled run that is still draining, or any unresolved effect, leaves its total unavailable. Active runs are excluded. |
|
|
284
|
+
| `metrics.fixRounds.medianPerMergedPullRequest` | Median count of `run-turn` operations after the first `open-pr` request, for each successful merge in the window. Evidence includes the run ID, pull request number, merge operation ID and fix-round count. Unmerged runs do not contribute. |
|
|
285
|
+
| `metrics.leadTime.medianHours` | Median hours from the last `cloving: ready` label before each completed ticket's close to that close. The command reads all issue timeline pages, including labels before the window. Evidence includes issue numbers and label and close times. An unreadable timeline or missing ready label leaves the value unavailable. |
|
|
286
|
+
| `metrics.phases.workerTurn.medianMinutes` | Median minutes from request to report for `run-turn` operations that end in the window, including failed operations. Evidence includes run IDs and operation IDs. |
|
|
287
|
+
| `metrics.phases.codeReview.medianMinutes` | Median request-to-report minutes for `wait-review` operations that end in the window. |
|
|
288
|
+
| `metrics.phases.merge.medianMinutes` | Median request-to-report minutes for `merge` operations that end in the window. This duration includes the merge check and CI wait; separate times are unavailable. |
|
|
289
|
+
| `metrics.cost.medianCompletedTicketUsd` | Median total actual run cost for tickets that close as completed in the window. Each ticket includes all of its ended attempts at report time, including older partial, blocked, failed and cancelled attempts. |
|
|
290
|
+
| `completedTicketCosts` | Each completed ticket's issue number, close time, total USD cost, contributing runs and turn prices, evidence and historical daily median ticket-cost baseline. An unknown turn price, unreadable run identity or absent run history leaves the cost null. Estimates never replace actual prices. |
|
|
291
|
+
| `metrics.flow.busyLaneShare` | Queue run active milliseconds divided by current lanes times window milliseconds. Runs start at `run.started` and end at their terminal event; crossing and ongoing runs are clipped to the window. Evidence names the workflow, current lanes and runs. |
|
|
292
|
+
| `metrics.flow.idleLaneHoursWithReadyTicket` | Elapsed hours with fewer active queue runs than lanes and at least one eligible ready ticket. An interval counts once even when several lanes are idle or several tickets are eligible. |
|
|
293
|
+
| `metrics.flow.readyWaitHours.dependency` | Sum of ticket-hours carrying `cloving: ready` while at least one issue in the ticket's current `Needs` lines is open. Tickets without `Needs` have no dependency wait. Evidence names tickets and dependencies. |
|
|
294
|
+
| `metrics.flow.readyWaitHours.noLane` | Sum of eligible ticket-hours while all current queue lanes are occupied. Eligibility requires the ready label and every needed issue closed. |
|
|
295
|
+
| `metrics.flow.peakActiveRuns` | Largest simultaneous active run count across all workflows in the window, with the run IDs at the first peak. |
|
|
296
|
+
| `metrics.flow.scheduleSkips` | Total `schedule.skipped` events in the window. `metrics.flow.scheduleSkips.<workflowId>` gives the count for each observed workflow, with workflow IDs and event sequences. |
|
|
297
|
+
| `metrics.flow.unsuccessfulStreak.current` | Number of consecutive last-ended runs whose outcome was not completed at the window end, including a streak starting before the window. Terminal time orders runs, with event sequence breaking ties. Evidence names the streak's runs. |
|
|
298
|
+
| `metrics.flow.unsuccessfulStreak.longest` | Longest unsuccessful streak among runs ending in the window. A completed outcome resets both streaks; partial, blocked, failed and cancelled outcomes extend them. |
|
|
299
|
+
| `ci.jobMinutes.localMacos` | Median job duration in minutes. The same key is available for `localLinux`, `hostedMacos` and `hostedLinux`. Evidence gives job IDs, run IDs, attempts, names, duration and limit. |
|
|
300
|
+
| `ci.jobLimitShare.localMacos` | Median of each job's duration divided by its own `timeout-minutes`. Also reported for `localLinux`, `hostedMacos` and `hostedLinux`. A job with no known limit contributes duration without a share. |
|
|
301
|
+
| `ci.runnerWaitMinutes.localMacos` | Median minutes from job creation to start, also reported for `localLinux`, `hostedMacos` and `hostedLinux`. |
|
|
302
|
+
| `ci.timeouts` | Jobs with conclusion `timed_out`, or duration at least their known limit. Each job counts once, with job and run IDs as evidence. |
|
|
303
|
+
| `ci.reruns` | Workflow runs whose latest attempt number exceeds one. Each run counts once at the latest attempt start (`run_started_at`, falling back to `updated_at`). Evidence includes run IDs and attempt numbers. |
|
|
304
|
+
| `operator.merges` | Merged pull requests with no completed daemon `merge` effect reporting `merged: true` or the daemon's merge commit SHA for that pull request number before report end. |
|
|
305
|
+
| `operator.labelChanges` | `labeled` and `unlabeled` events for `cloving:` labels with no daemon `label` effect ending within two minutes for the same issue. This is a time match, recorded in `semantics.operatorLabels`; it does not identify the actor. Evidence gives issue numbers, event IDs, label and change type. |
|
|
306
|
+
| `quality.mainFirstPassShare` | CI runs on `main` that passed on attempt 1, divided by all CI runs created in the window. Later successful attempts do not count as first passes. No runs gives unavailable. Evidence includes run IDs, commits and first-attempt conclusions. |
|
|
307
|
+
| `quality.flakyFailures` | Failed job names and commits with a later successful attempt. Each job-name and commit pair counts once. Evidence includes test names from the failed logs, the commit, run IDs and failed and successful job IDs. |
|
|
308
|
+
| `quality.realFailures` | Failed job names and commits without a later successful attempt. Repeated failed attempts count once per job-name and commit pair. Evidence includes the failed job IDs and test names. |
|
|
309
|
+
| `quality.revertedPullRequests` | Merged pull requests in the window whose title starts with `Revert "`. Evidence gives the pull request numbers. |
|
|
310
|
+
| `quality.reopenedTickets` | Reopened issue events in the window after an earlier completed close. Evidence gives issue numbers, event IDs and the earlier close time. |
|
|
311
|
+
| `quality.reviewScore.round1` | Median score reported by the first `wait-review` operation in each run. `round2` and later keys use the operation order in that run. The report time selects the window. Evidence includes run IDs, operation IDs, event sequences and scores. |
|
|
312
|
+
|
|
313
|
+
Quality values have the same metric fields and seven-day baseline as other metrics. First-pass shares compare directly with daily shares. Failure, revert and reopen counts compare their daily equivalents. Review scores compare daily medians. CI data comes from the workflow named `CI` on `main`, with each run attempt read separately. Closure reasons come from issue events, with a GraphQL close-event read when REST omits the reason. An unreadable close reason leaves closure and reopen values unavailable.
|
|
314
|
+
|
|
315
|
+
Failure metrics use job completion times. The report scans all run pages and selects recent run activity, including completions and reruns of older runs. First-pass shares use run creation times. Ticket costs count each ticket once at its latest completed close before the report end. Repeated completed closes still count separately toward ticket throughput.
|
|
316
|
+
|
|
317
|
+
The report reads at most 50 distinct failed job logs, with a 2 MB output limit for each log. `quality.jobLogs` gives `read`, `notRead`, `limit` and `maximumBytes`. Each failed job without readable names uses `unknown`. Unread and unreadable logs do not erase known job failures. Logs use the `Failed tests:` list from the quality gate.
|
|
318
|
+
|
|
319
|
+
Flow uses the current queue workflow and lane setting and the current ticket bodies, as recorded in `semantics`; earlier settings and bodies are not reconstructed. Ready-label intervals come from all issue timeline pages, including removed and reapplied labels. Dependency closure times come from the current issue records; an open dependency remains blocking. Issue discovery includes every issue so an old, still-ready ticket is retained. This definition uses the label and dependency conditions regardless of ticket closure or assignment. Ready wait sums ticket-hours, while idle time measures elapsed hours. Hours and skip counts compare their per-day equivalent with the baseline; busy share, peak and streak values compare directly. Ready-history baselines start at repository creation; idle and no-lane baselines require both GitHub and daemon history. Unreadable timelines, dependencies or queue identity leave affected values unavailable while independent daemon values remain readable.
|
|
320
|
+
|
|
321
|
+
Every metric has `value`, `comparisonValue`, `baseline` and `evidence`. Counts retain their requested-window totals in `value`; `comparisonValue` is their equivalent per 24 hours. Medians are not scaled. The baseline uses the seven consecutive 24-hour periods immediately before the window, anchored at the same time of day in UTC. It contains the median and the band from median minus three times the median absolute deviation to median plus three times that deviation. Only values strictly outside the band receive `mark: "outside"`. Individual run and ticket costs use their respective daily median cost bands. With fewer than five complete observed days, `history` is `short`, the median and band are null, and there is no mark. Empty observed days count as zero for counts; days without samples, or with an unknown sample, do not establish a daily median. An unrepresentable numeric band has unavailable history and no mark. Daemon history starts at its earliest retained event; GitHub history starts at repository creation. Ticket-cost history starts at the later of those two dates.
|
|
269
322
|
|
|
270
323
|
Evidence includes the contributing run IDs and event sequences, issue numbers or pull request numbers. Baseline evidence is separate from current-window evidence. Run cost details also expose each turn's operation ID. The daemon event read is pinned to the first page's latest sequence; later appended events are excluded. Run status and GitHub sources are separate reads, so the report is not an atomic cross-source snapshot.
|
|
271
324
|
|
|
272
325
|
Each GitHub read uses the existing retry rules: transient network errors and HTTP 500, 502, 503 and 504 receive up to three attempts, with growing waits of 30 and 60 seconds. Read failure, invalid data, an unknown actual price or missing repository context is represented as `unavailable` with a null metric value, rather than zero. A failed source does not hide readable sources. `sources` shows which reads succeeded; the command exits zero when it produces a report, including one with unavailable sources. Invalid command arguments exit two.
|
|
273
326
|
|
|
274
|
-
|
|
327
|
+
CI usage reads the workflow named `CI` on every branch, including every attempt of runs with recent activity. Job completion time selects job samples. Labels containing `self-hosted` identify local runners; other runners are hosted. macOS and Linux come from explicit system labels, falling back for hosted runners to the workflow's image (`runs-on`). Unrecognized runner data leaves job metrics unavailable. Limits come from the workflow file at the run's commit through the GitHub contents API. Only JSON documents are parsed; non-JSON workflows and jobs without numeric limits have duration and wait samples without shares. An unreadable workflow leaves shares and timeouts unavailable while duration, wait and rerun values remain independent. An unreadable job source preserves rerun counts. Unreadable run activity makes CI usage unavailable. `sources.github.ciUsage` reports the all-branch run read. `sources.github.ciUsageJobs` and `sources.github.ciUsageWorkflows` report its job and workflow reads, with failure reasons. These statuses are separate from `ci` and `jobs`, which report quality reads on `main`.
|
|
328
|
+
|
|
329
|
+
Operator values combine GitHub merges and repository issue-label events with daemon `effect.reported` events joined to their requests. Missing daemon history makes operator values unavailable. Their baselines start at the later of daemon history and repository creation. CI and operator values use the same seven-day median, band, evidence and short-history rules as other report values. CI durations, limit shares and waits compare daily medians; timeout, rerun and operator counts compare daily equivalents. The `coverage` object has no remaining unimplemented report sections. The report performs no model call, writes no state and changes no queue.
|
|
275
330
|
|
|
276
331
|
## Daily development
|
|
277
332
|
|
|
278
|
-
`cloving start`
|
|
333
|
+
`cloving start` compiles and registers only project and user workflows. The start guide lists each registered workflow with a run command that matches its input contract. With no workflow, the service still starts and prints "No workflow. Run: cloving init". Status continues to show stored runs after their workflows have been removed.
|
|
279
334
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
335
|
+
To add, change or remove a workflow file while the service runs, run `cloving reload`. The service checks and compiles the workflow files again in a child process. New runs use the new bundle. A run that started before the reload stays on the bundle of its pin, and its agent turn continues. When a workflow file gets a new refusal, for example a compile error, the reload keeps the current workflows and shows the reason. A change of the queue workflow or of a schedule needs a restart. After you remove all workflow files, a reload removes all workflows. `cloving status --json` shows the current `bundleDigest`.
|
|
336
|
+
|
|
337
|
+
The reload also reads the settings files and the profiles file again. It applies changes of `profiles`, `fallbackModels`, `tokenPrices` and `workflows.folder`. New turns use the new values, and a turn in work keeps the values of its start. A changed `workflows.folder` applies to the workflow part of the same reload. The reply lists these fields in `reloadedFields`. It lists each other changed field in `restartFields`, and the service keeps the old value of that field until a restart. The environment variables of the start keep their precedence over the files. An invalid settings file, an invalid profiles file or a profile that names a harness with no worker at the start of the service refuses the reload with its code, for example `invalid-config-json`, `invalid-profiles` or `harness-no-worker`. Then nothing changes.
|
|
338
|
+
|
|
339
|
+
Use `cloving init` to choose and configure a template. The `develop` template supports ticket input, queue selection, review and merge choices. The `idea-to-issue` template researches an idea and hands the resulting issue to a declared development workflow. The commands below assume those templates have been copied and configured:
|
|
284
340
|
|
|
285
341
|
```sh
|
|
286
342
|
cloving start # terminal 1, in the repository
|
|
287
|
-
cloving run develop
|
|
288
|
-
cloving run develop
|
|
289
|
-
|
|
290
|
-
cloving run
|
|
291
|
-
cloving run develop-prd --prompt "Show the cost of each run on the watch page"
|
|
343
|
+
cloving run develop --ticket TICKET_ID # terminal 2
|
|
344
|
+
cloving run develop --next # select the next ready ticket
|
|
345
|
+
printf '%s\n' '{"idea":"Show the cost of each run on the watch page"}' > idea.json
|
|
346
|
+
cloving run idea-to-issue --input idea.json
|
|
292
347
|
cloving watch # the live page, also started by cloving start
|
|
293
348
|
cloving questions
|
|
294
349
|
cloving approve DECISION_REF --expected-revision N --generation N --subject-digest DIGEST
|
|
@@ -299,17 +354,19 @@ The rule: read the diff before you approve.
|
|
|
299
354
|
|
|
300
355
|
Claude turns have web research tools by default, an empty GitHub CLI configuration folder, and no GitHub token environment variables. This is not a sandbox: a turn can still find other credentials. The PRD refusal rules catch the listed private text and common sensitive forms; unlisted private names can pass. A `post-uncertain` result requires checking GitHub before trying another run.
|
|
301
356
|
|
|
302
|
-
`cloving status
|
|
357
|
+
`cloving status --active` lists only the runs that are not `completed`, `failed` or `cancelled`. It uses the same order and format as `cloving status`. The service selects the active runs before it builds a run view. Thus it makes no view query for a finished run. The number of queries does not change with the number of finished runs, but the service still reads the stored state of each run. `--active` works with `--json`, `--limit` and `--after`. With `--json`, one request returns one page of active runs and its `next` cursor.
|
|
358
|
+
|
|
359
|
+
`cloving status RUN_ID --json` includes `run.input`, and `cloving status --json` includes `input` on each listed run. It is the normalized submission admitted with the run, such as `{"ticket":"297"}` for a ticket workflow or the submitted fields of another declared workflow. It survives service restarts and excludes resolver-added ticket text and repository paths. Older runs without a stored submission show `null`. The text status of one run shows `Input:` as compact JSON, limited to the first 200 characters with `…` appended when longer. Terminal control and hidden format characters are escaped.
|
|
303
360
|
|
|
304
361
|
### The ticket command
|
|
305
362
|
|
|
306
363
|
`CLOVING_TICKET_COMMAND` (a JSON list of texts) names the ticket command. The contract of a ticket command:
|
|
307
364
|
|
|
308
365
|
- It gets a ticket ID as its last argument and prints the text of the ticket.
|
|
309
|
-
-
|
|
310
|
-
- For `develop
|
|
366
|
+
- The `develop` template uses the first ticket line as the pull request title, removes leading Markdown heading markers and limits it to 200 characters.
|
|
367
|
+
- For `develop`, a line `GitHub issue: <owner>/<repository>#<number>` makes the pull request reference that issue. Cloving closes it after a merge only when the worker reports complete work.
|
|
311
368
|
|
|
312
|
-
The daemon runs the ticket command when it admits a run. The printed text becomes the stored input of the run, so a later change of the ticket does not change the run. A ticket that the command does not give is refused with `ticket-not-available`. With no ticket command, `develop
|
|
369
|
+
The daemon runs the ticket command when it admits a run. The printed text becomes the stored input of the run, so a later change of the ticket does not change the run. A ticket that the command does not give is refused with `ticket-not-available`. With no ticket command, `develop` is refused with `ticket-source-not-configured`. A ticket ID has letters, digits and the characters `. _ : -` only.
|
|
313
370
|
|
|
314
371
|
This example ticket command reads a GitHub issue. Save it as `~/.local/bin/github-ticket`, and make it executable:
|
|
315
372
|
|
|
@@ -328,9 +385,11 @@ Then start the service with the setting:
|
|
|
328
385
|
CLOVING_TICKET_COMMAND='["github-ticket"]' cloving start
|
|
329
386
|
```
|
|
330
387
|
|
|
331
|
-
`cloving run develop
|
|
388
|
+
`cloving run develop --next` uses the reserved ticket ID `next`, just like `--ticket next`. Set `CLOVING_NEXT_COMMAND` to a JSON list naming your selection command and its arguments. The daemon adds no argument. The command chooses a ready ticket in your tracker and prints its ID; the daemon trims it and reads the ticket with `CLOVING_TICKET_COMMAND`. Both commands share the resolver's 30-second deadline. Selection logic stays in your command, and each invocation submits only one run.
|
|
389
|
+
|
|
390
|
+
Set `CLOVING_QUEUE_SECONDS` to a whole number from 10 to 3600 to poll for ready tickets. The queue starts the declared workflow with `"queue": true` and requires both ticket commands when that workflow exists. If no workflow declares it, no queue starts, even when the interval is set. `CLOVING_QUEUE_LANES` sets the number of simultaneous runs, from 1 to 4, and requires `CLOVING_QUEUE_SECONDS`; its default is 1. For example, `CLOVING_QUEUE_LANES=4` admits at most one new ticket each cycle until four lanes are busy. Each run has its own branch and work tree. Manual submissions to the queue workflow share this limit and receive `workflow-active` when all lanes are busy. A ticket already being developed receives `ticket-active`. After a restart that moves the queue to another workflow, active runs of earlier queue workflows still occupy lanes and exclude their tickets.
|
|
332
391
|
|
|
333
|
-
Set `
|
|
392
|
+
Set `queue.dailySpendLimitUsd` in project or private configuration, or `CLOVING_QUEUE_DAILY_SPEND_USD`, to a positive finite USD limit. It requires `CLOVING_QUEUE_SECONDS`. At 85 percent of this limit, the queue holds new runs until spend falls below the threshold. Spend covers worker turns of queue workflows settled in the last 24 hours, using each reported price or its token-price estimate. Runs in work continue, so spend can exceed the limit. Status and watch show spend, the limit, unknown costs and turns in work. Unknown costs are never counted as zero; when every settled turn has unknown cost, they show `Price not known`. The window and hold are reconstructed from stored settlements after restart. Runs of other workflows do not count.
|
|
334
393
|
|
|
335
394
|
The optional declaration field `queue` is a boolean. `"queue": true` requires a field named `ticket` with `"type": "ticket"` (`queue-needs-ticket-field`), and every other input field must be optional (`queue-input-incomplete`). Two queue declarations stop startup with `queue-workflow-conflict`. `cloving doctor` requires `next-command` and `queue-interval` whenever a declared workflow takes the queue.
|
|
336
395
|
|
|
@@ -338,7 +397,7 @@ Before enabling more than one lane, update the next-ticket command to honor `CLO
|
|
|
338
397
|
|
|
339
398
|
In the ticket text returned by `CLOVING_TICKET_COMMAND`, each `#N` in a sentence starting with **Needs** inside `## Dependencies` is a hard dependency. For example, `Needs #123 and #124.` waits until both GitHub issues close. Other references and sections do not create dependencies. Cloving reads dependency state with `CLOVING_GH_COMMAND` (default `gh`); an unavailable or invalid response prevents admission. An open dependency returns `ticket-dependency-open` and puts the ticket in the skip list. Waiting tickets are checked again each cycle with a free lane, so a closed dependency makes its ticket eligible again.
|
|
340
399
|
|
|
341
|
-
`cloving status` and watch display busy lanes and skipped tickets with their reasons. A pending self-update holds new admissions while active lanes drain. Three unsuccessful runs in a row, counted in the order they finish, stop the queue; a successful handoff clears the streak. Ordinary restarts preserve it. After inspecting and reconciling the failures, start with `--reset-queue
|
|
400
|
+
`cloving status` and watch display the queue state, busy lanes and skipped tickets with their reasons. A pending self-update holds new admissions while active lanes drain. Three unsuccessful runs in a row, counted in the order they finish, stop the queue; a successful handoff clears the streak. Ordinary restarts preserve it. After inspecting and reconciling the failures, run `cloving queue resume`, or start with `--reset-queue`, to clear the streak. A conflict caused by an earlier lane's merge returns its diagnostics to a fix round. The merge steps of one repository take turns: a step waits until the earlier step ends, and then it merges `main`, runs the merge check, pushes and waits for CI. Lanes do not add CI runners or parallelize turns within one run.
|
|
342
401
|
|
|
343
402
|
An empty selection gives `no-ready-ticket`; a failed command gives `next-ticket-not-available`. Missing configuration gives `next-source-not-configured`. Multiple IDs, an invalid ID, or `next` as the selected ID give `invalid-ticket-id`. Use only one of `--next`, `--ticket`, `--prompt` and `--input`.
|
|
344
403
|
|
|
@@ -346,26 +405,28 @@ A saved harness named `grok` runs `grok --output-format streaming-messages-json
|
|
|
346
405
|
|
|
347
406
|
Grok token counts come only from the terminal result, including its subagents. Input includes uncached input and cache creation; cache reads and output remain separate. Missing, all-zero or stderr-warned incomplete usage shows `Token usage not known`. An estimate requires complete usage attributed to exactly one model with a configured price. Mixed models and missing prices show `Price not known`. Grok uses token-based estimates and ignores its projected cost field. No Grok model prices are built in.
|
|
348
407
|
|
|
349
|
-
###
|
|
408
|
+
### Human review with a local branch
|
|
350
409
|
|
|
351
410
|
Worker turns retry an exact Codex capacity refusal or a Claude overload after 60 seconds, then 180 seconds. Claude worker turns also retry a failed result whose text starts with `API Error: Can't reach the API server`: the first retry waits 10 minutes and the second waits 40 minutes. The retry number selects the wait for its kind, with at most three attempts across both kinds. Other failures are not retried. Each wait starts after the failed attempt ends. Stopping during a wait returns `stopped`; a daemon restart fails the recorded operation for existing recovery.
|
|
352
411
|
|
|
353
412
|
Each retry keeps the work tree, profile, budget and limits, and starts a new session with a continuation line before the full prompt. After any network failure, every later attempt gets the network continuation, which asks it to check earlier commits, pushes, review comments and messages, avoid repeating completed writes, and stop to report a write whose result is unknown. It also gets fresh git evidence for commits since this turn's first attempt. Cloving fetches the branch from `origin` and marks each commit `pushed`, `not pushed` or `unknown`; an absent origin branch means `not pushed`. Each git command has a 30-second limit and is cancelled by drop. Failed reads give explicit unknown evidence.
|
|
354
413
|
|
|
355
|
-
Before a retry, Cloving checks the work tree's git index lock, including linked work trees.
|
|
414
|
+
Before a retry, Cloving checks the work tree's git index lock, including linked work trees. Capacity and network retries never remove a lock: `worktree-index-locked` records its path and tells the operator to remove it when no git process uses the work tree. Before a Claude resume after a daemon restart or a dead turn process, Cloving stops same-user processes whose working directories are in the turn work tree, waits up to 15 seconds after SIGTERM, then sends SIGKILL. Cloving does the same cleanup before it reports `claude-turn-interrupted` for a turn that it cannot resume, so a later turn does not share the work tree with an earlier process. A cleanup failure gives its own reason instead of `claude-turn-interrupted`. The daemon itself and processes outside that tree are excluded. Cloving removes a work tree index lock only when it identified the lock owners before cleanup, those owners have exited, and the lock has not changed. A lock with an unknown owner, including one whose owner closed its descriptor, stays in place and reports `worktree-index-locked`; inspect its owner before removing it manually. Stopped process IDs are recorded in `resume-processes.json` in the turn folder. An unreadable index path gives `worktree-index-unknown`. Neither failure starts another attempt. The step keeps one operation identity and sums usage across attempts. Private turn journals, status text and JSON, and watch retain each attempt's model, token counts, cost estimate and `retryKind` (`capacity`, `network`, or `null` for other results). Older attempts without the field show no kind. Attempt kinds appear after the turn ends. Resumed attempts also show `resumedAfter: daemon-restart` in status text, JSON and watch.
|
|
356
415
|
|
|
357
416
|
`CLOVING_FALLBACK_MODELS` accepts a JSON array of at most three nonempty model names, for example `'["gpt-6-astra"]'`. Without the setting or with `[]`, every attempt keeps the main model. The first attempt and first retry use the main model; each later attempt uses the next configured fallback within the existing attempt limit. With three attempts, only the first fallback can be used. The worker command must explicitly name a model with `-m NAME`, `--model NAME` or `--model=NAME`; otherwise it stays unchanged and the private journal records `fallback-model-unavailable`. Fallbacks apply only when the preceding attempt ended with a capacity refusal. A network retry keeps the model of the configured command. A fallback model can have a higher price. Each attempt's estimate uses its own model's price; an unknown price or missing token count leaves the total estimate unknown. Malformed settings refuse daemon start with `invalid-fallback-models`.
|
|
358
417
|
|
|
359
|
-
A
|
|
418
|
+
A develop template copy configured for human review and the local-branch merge option has up to four review rounds. Each round does one Claude Code turn in the work tree of the run, on its generated task branch, and then opens one approval. The first round makes the work tree. The approval identifies the immutable review subject, including its target and commit. Read that commit’s diff before you decide. The decision has these results:
|
|
360
419
|
|
|
361
420
|
- An approval completes the run. It does not merge the branch. Merge the branch yourself.
|
|
362
|
-
- A denial with a feedback text (`--text`) in
|
|
363
|
-
- A denial with no text, or a denial in round
|
|
421
|
+
- A denial with a feedback text (`--text`) in rounds 1 to 3 starts the next round. The Claude worker gets the feedback text and adds commits to the same branch.
|
|
422
|
+
- A denial with no text, or a denial in round 4, ends the run.
|
|
364
423
|
|
|
365
424
|
The worker is not confined. It runs the `claude` command of the search path as the current user, with file edits and shell commands permitted in the work tree and a spend limit of 5 USD for each turn. `CLOVING_CLAUDE_COMMAND` (a JSON list of texts) replaces the command.
|
|
366
425
|
|
|
367
426
|
Single-run status (`cloving status RUN_ID`, also with `--json`) and watch show each worker command call and its run totals. Token counts retain the reported input, cache read and output categories separately. Codex input includes cached tokens; cache read tokens are not added to input tokens. These selected counts are not complete billing usage or a record of all subagent work. Missing or invalid fields show `Token usage not known`. Costs show the worker-reported USD price when available, otherwise `≈ 7.82 USD (estimate)` when an estimate is available, otherwise `Price not known`; a reported zero shows `0.00 USD`. Totals for an unfinished run are labeled `so far`. JSON uses `null` for unknown numeric values, retains the total reported price field `claudeCostUsd`, and adds `costDisplay` to the run and each worker turn.
|
|
368
427
|
|
|
428
|
+
The totals of a run stay in the service state after the retention rule moves its operation records. When a turn folder of the run is in the `journal` folder of the archive, single-run status shows `Turn details are archived in the journal folder of the archive: <folder>`, and JSON adds `run.turnDetails` as `{ "state": "archived", "folder": "<archive>/journal" }`. With the `delete` action, status shows `Turn details were deleted by the retention rule`, and JSON adds `{ "state": "deleted" }`. The daemon shows a deletion only for a finished run that ended before the retention period and has no turn folder in the state folder. Runs with kept records have no `turnDetails` field.
|
|
429
|
+
|
|
369
430
|
The built-in table uses standard short-context prices read on **2026-10-18** from the [OpenAI pricing page](https://openai.com/api/pricing/), in USD per million tokens:
|
|
370
431
|
|
|
371
432
|
| Model | Input | Cached input | Output |
|
|
@@ -446,19 +507,21 @@ separate starting commits; concurrent runs on one branch do not isolate their
|
|
|
446
507
|
commits. Index flags inside submodules and other settings that hide changes
|
|
447
508
|
are outside these checks. Every GitHub worker method refuses `branch:` targets
|
|
448
509
|
with `branch-target-not-supported`, so this target adds no Cloving push or merge
|
|
449
|
-
step.
|
|
510
|
+
step. Each project or user workflow declares its own targets.
|
|
450
511
|
|
|
451
|
-
### Pull requests of `develop
|
|
512
|
+
### Pull requests of `develop`
|
|
452
513
|
|
|
453
|
-
|
|
514
|
+
The default `develop` template uses automatic review without an approval. The GitHub worker makes the work tree from the newest commit of the default branch of `origin`. After the Claude turn, the worker pushes the branch and opens a pull request. The title and the referenced issue come from the ticket text (see "The ticket command"). The pull request body uses `Refs owner/repository#N`, so the merge itself does not close the issue. Then the worker waits for the Greptile review of the pushed commit, and asks for a review with a comment after 5 minutes.
|
|
454
515
|
|
|
455
|
-
When the ticket names a GitHub issue, the workflow adds `cloving: in progress` after preparing the work tree and removes `cloving: ready` and `cloving: blocked`. A blocked run adds `cloving: blocked` and removes `cloving: in progress`.
|
|
516
|
+
When the ticket names a GitHub issue, the workflow adds `cloving: in progress` after preparing the work tree and removes `cloving: ready` and `cloving: blocked`. A blocked run adds `cloving: blocked` and removes `cloving: in progress`. A failed label operation throws and can fail the template run. Cloving creates the labels it adds or removes with the fixed color `ededed`; existing labels have their color and description reset by `gh label create --force`.
|
|
456
517
|
|
|
457
518
|
The last worker report must end with exactly one line: `Ticket status: complete` or `Ticket status: partial`. A partial report must put `Remaining:` immediately before a list with one `- ` item per line, followed by the status line. The worker records the parsed status and remaining items before shortening the summary, so summary limits cannot remove those fields. If the preserved fields exceed the result byte limit, the turn fails with `claude-result-too-large` and retains bounded cost metadata; the full report stays in the private turn log. Older recorded turns still use summary parsing. Missing, repeated, unknown or malformed status reports count as partial with the remaining item "The worker report has no ticket status line."
|
|
458
519
|
|
|
459
520
|
After a merge, a protected GitHub operation updates the issue body and labels. Complete work closes the issue with reason `completed` and adds "Completed in pull request #M." to `## Cloving status`. Partial work keeps the issue open and appends `- Pull request #M: partial. Remaining: ...` to that section at the end of the body, preserving earlier partial lines and other body text. Items are separated by semicolons. The issue privacy check runs before new remaining text is written; a refusal uses "Remaining work is in the private run report." instead. No issue comment is posted. Status writes add and remove only workflow labels, preserving unrelated label edits. Before a body write, Cloving rereads the issue and refuses a changed body with `github-issue-conflict`; the merged outcome records `issueUpdate: failed`. GitHub does not support conditional PATCH requests for this endpoint, so this check cannot make the read and write atomic.
|
|
460
521
|
|
|
461
|
-
Partial work removes `cloving: in progress` and adds `cloving: ready`, so the next queue cycle can select the same issue and read its remaining work from the issue body. The third partial run adds `cloving: blocked` instead of `cloving: ready`. Completion removes these workflow labels. Status operations reconcile the pull request number in the stored history after a restart to avoid duplicate writes. The
|
|
522
|
+
Partial work removes `cloving: in progress` and adds `cloving: ready`, so the next queue cycle can select the same issue and read its remaining work from the issue body. The third partial run adds `cloving: blocked` instead of `cloving: ready`. Completion removes these workflow labels. Status operations reconcile the pull request number in the stored history after a restart to avoid duplicate writes. The unmodified develop template declares an effect limit of 31 units.
|
|
523
|
+
|
|
524
|
+
When a worker turn ends with `claude-turn-interrupted`, the develop template runs the turn again once in the same work tree. This occurs when the daemon cannot resume an open turn after a restart, for example when the turn has no recorded session. The prompt of the new turn tells the worker that the earlier turn stopped before its report, and that the work tree holds its work. A second interruption of the same turn ends the run as blocked with the reason `turn-interrupted` and adds `cloving: blocked`. Other turn failures fail the run.
|
|
462
525
|
|
|
463
526
|
Partial history comes only from a hidden HTML comment at the end of the issue body, beginning with `cloving-status`. Its JSON object has `version: 1`, a `partialRuns` array of pull request numbers and remaining-item lists, and an optional `completedPullRequest`. Double hyphens and greater-than signs in JSON strings are escaped so they cannot end the comment. Each write regenerates the readable section from this data and replaces the exact previously generated section. Other Markdown stays unchanged, including status examples, lists, tables, HTML and unclosed fences. Missing, broken or unknown metadata counts as zero earlier partial runs and is replaced on the next write; readable text is never used to reconstruct history. A block followed by other issue text is left unchanged and counts as missing terminal metadata.
|
|
464
527
|
|
|
@@ -468,6 +531,20 @@ Merged runs retain `handoff_requested` with `ticketStatus: complete` or `partial
|
|
|
468
531
|
|
|
469
532
|
To resume a queue stopped at this limit, stop the service with Control-C, inspect the failures and reconcile the affected issues, then run `cloving start --reset-queue` with the same repository, runtime and queue settings. This clears the failure streak once and preserves tracked commands. Ordinary restarts, including automatic self-updates, preserve the count. Resetting the queue does not change issue labels or retry blocked issues.
|
|
470
533
|
|
|
534
|
+
### Queue control
|
|
535
|
+
|
|
536
|
+
The operator controls the queue of a running service with three commands. Each command uses the service protocol, and `--json` prints one JSON object.
|
|
537
|
+
|
|
538
|
+
- `cloving queue [--json]` shows the state of the queue: `running`, `stopped`, `draining` or `drained`. It also shows the busy lanes, the failed runs in a row and, for a stopped queue, the reason. `cloving status` and the watch page show the same state.
|
|
539
|
+
- `cloving queue resume [--command-id <id>] [--json]` sets the failure count to 0 and ends a stop or a drain. The next queue check can start a ready ticket. No restart is necessary.
|
|
540
|
+
- `cloving queue drain [--command-id <id>] [--json]` makes the queue start no new run. The runs in work continue to their end. When no lane is busy, the queue journal records the drain time, the service log shows `Queue drained` one time, and the state changes to `drained`. Until the queue records that time, the state stays `draining`.
|
|
541
|
+
|
|
542
|
+
A drained queue is a safe point for a restart. The drain stays in place after a restart. `cloving queue resume` or `cloving start --reset-queue` ends it. A drain does not stop manual runs. A manual run that starts after the drain time shows `draining` until the run ends.
|
|
543
|
+
|
|
544
|
+
With no `--command-id`, the command makes an ID. The text output prints it on standard error, and the JSON result includes it as `commandId`. The queue journal keeps the newest 32 command IDs across restarts. A repeated command with a kept ID does not apply the command again, and the reply shows the current queue state with `replayed: true`. A different command with a kept ID gets `conflicting-command`. The queue applies a command with an older ID as a new command.
|
|
545
|
+
|
|
546
|
+
A queue that stopped on an error shows the error as the reason and refuses commands until a restart. An invalid queue journal and a queue command that the journal cannot save are two examples of these errors.
|
|
547
|
+
|
|
471
548
|
At the confidence score 5/5, the worker runs the local merge check and waits for CI of the exact head it will merge, including an updated head pushed after merging the default branch. When CI passes, it merges the pull request with a merge commit, with no human approval. Then it removes the remote branch, the work tree and the local branch. With a lower score, the Claude worker gets the summary and the findings of the review for one more round. After three such rounds, or after 60 minutes with no review, the run stops and the pull request stays open.
|
|
472
549
|
|
|
473
550
|
Set `CLOVING_REQUIRED_CHECKS` to a JSON list of check run names, such as `["quality", "quality_linux"]`, to require those checks. Without the setting, all GitHub Actions checks on the head commit are required. The newest run of each name decides; `success`, `neutral` and `skipped` pass. With no setting and no Actions checks after a 60-second grace period, a repository without CI can merge. A configured missing check keeps waiting. CI is polled every 30 seconds with a separate 90-minute limit. A timeout returns `ci-pending` and blocks without a fix round.
|
|
@@ -476,7 +553,7 @@ When a GitHub Actions check fails in its first workflow attempt, Cloving request
|
|
|
476
553
|
|
|
477
554
|
A second failure returns `ci-failed` with the outputs of both attempts, including failed check names, failed steps and failed log tails, with private texts hidden and at most 6,000 characters in total. Checks outside GitHub Actions or without an Actions run link retain the immediate failure behavior. The failure starts a worker fix round that must repair CI, including failures the pull request did not cause, and commit the fix. The new commit receives a new Greptile review and CI gate. Review, local check, conflict and CI repairs share the existing limit of three fix rounds.
|
|
478
555
|
|
|
479
|
-
The watch board
|
|
556
|
+
The watch board preserves the displays of historical pull-request runs, including blocked runs in `Stopped`. A validated local merge report shows `PR merged · #N`. A later completed run for the same established GitHub issue must have its own validated merge report to show `Ticket completed by later run`. The original and later run have separate links. Either local proof prevents a GitHub read. These marks preserve the recorded run outcome.
|
|
480
557
|
|
|
481
558
|
Otherwise, the board reads the recorded pull request with `CLOVING_GH_COMMAND` (default `gh`). It validates the PR and issue identities against the configured repository's local origin. The first queued or active read shows `Checking PR`. A confirmed merge shows `PR merged · #N`; a failed read shows `PR status unavailable`. An unmerged PR shows `Needs attention`. A separate `Stale` mark appears when the last successful unmerged observation is older than 120 seconds, including after a failed refresh. A successful refresh resets its age. Confirmed merges never become stale.
|
|
482
559
|
|
|
@@ -486,10 +563,14 @@ The GitHub worker does not push a change that has the path of the home folder in
|
|
|
486
563
|
|
|
487
564
|
## Continuous process
|
|
488
565
|
|
|
489
|
-
In a continuous process, Cloving develops one ticket after the next with `develop
|
|
566
|
+
In a continuous process, Cloving develops one ticket after the next with `develop`. Keep the workflow outside this public repository. In a private repository, run `cloving templates copy develop`. From the Cloving repository, set `cloving config set workflows.folder "$WORKFLOW_FOLDER"`, where `WORKFLOW_FOLDER` is the absolute folder containing that copy, and restart the service. The setting stays in the operator’s private settings file. Do not commit a workflow copy here.
|
|
567
|
+
|
|
568
|
+
The unmodified template takes a ticket, selects from the queue (`"queue": true`), accepts Greptile at 5/5, lets Cloving merge after the checks, and returns partial tickets to the queue. Configure the ticket command, next-ticket command and queue interval in the operator’s settings. The queue starts only the declared queue workflow, `develop`.
|
|
569
|
+
|
|
570
|
+
Use one terminal session for the service that stays open, for example a `tmux` session. Do these steps for each issue:
|
|
490
571
|
|
|
491
572
|
1. Write a small issue: one behavior, clear criteria that a test can check, and the first tests. The prompt "Write a ticket for Cloving" helps.
|
|
492
|
-
2. Run it: `cloving run develop
|
|
573
|
+
2. Run it: `cloving run develop --ticket ISSUE_NUMBER`.
|
|
493
574
|
3. Follow the run on the watch page, or with `cloving status RUN_ID` and `cloving events RUN_ID --follow`.
|
|
494
575
|
4. Check the merge. The run completes when the GitHub worker merges the pull request. The watch page shows the number of the pull request of the run (`PR_NUMBER`). It is also `pullRequest.number` of the run in `http://127.0.0.1:3663/data.json`. The pull request number and the issue number are different.
|
|
495
576
|
- Make sure that the pull request is merged: `gh pr view PR_NUMBER --json state,mergedAt`.
|
|
@@ -502,39 +583,27 @@ When a run stops and the pull request stays open, read the review. Fix the work
|
|
|
502
583
|
|
|
503
584
|
Know these limits before you start:
|
|
504
585
|
|
|
505
|
-
- The cost limit of each Claude turn is 5 USD. A run of `develop
|
|
586
|
+
- The cost limit of each Claude turn is 5 USD. A run of `develop` can have up to four Claude turns. `CLOVING_CLAUDE_COMMAND` changes the command and its limit.
|
|
506
587
|
- The text of a pull request is public in a public repository. The worker gets an instruction to write no local file path in a file or in a commit message.
|
|
507
588
|
- `CLOVING_PRIVATE_TEXTS` adds texts that the GitHub worker refuses to push, for example the names of private projects. The path of the home folder is always refused.
|
|
508
|
-
-
|
|
589
|
+
- The default develop workflow runs `checks.beforeMerge` before merging. With no configured command, it stops with `check-not-configured` and leaves the pull request open. This repository commits `["npm", "run", "check:quality"]` as that command and requires the CI checks `quality` and `quality_linux` in `.cloving/config.json`. An environment or private-file override takes precedence.
|
|
509
590
|
|
|
510
591
|
## Prompts for a coding agent
|
|
511
592
|
|
|
512
593
|
Copy a prompt, replace the words in capital letters, and give it to a coding agent.
|
|
513
594
|
|
|
514
|
-
### Set up
|
|
595
|
+
### Set up a repository
|
|
515
596
|
|
|
516
|
-
|
|
517
|
-
Set up Cloving for my repository REPOSITORY_PATH. Ask me for each value that you do not know. Do not push, publish or merge anything in this setup.
|
|
518
|
-
|
|
519
|
-
1. Check the platform: macOS or Linux on arm64 or x64, with the Node and npm versions of "engines" in package.json of Cloving. Check that git and the claude command work. If I want develop-issue, check that gh has a login and that Greptile reviews the GitHub repository.
|
|
520
|
-
2. If I have no Cloving checkout, clone https://github.com/cloving-ai/cloving-ai.git to ~/cloving. In the checkout, run: npm ci --ignore-scripts
|
|
521
|
-
3. Write a launcher ~/.local/bin/cloving that runs src/cli.ts of the checkout with the correct node program, and make it executable. Do not use npm link. Make sure that ~/.local/bin is on the search path and that "cloving --version" works.
|
|
522
|
-
4. Ask me which tracker has my tickets. Write a ticket command for that tracker in ~/.local/bin. The command gets a ticket ID as its last argument and prints the text of the ticket. For develop-issue, the first line is "# " and the title, and one line is "GitHub issue: OWNER/REPOSITORY#NUMBER". Test the command with one ticket ID, and show me the output.
|
|
523
|
-
5. Start the service in a terminal session that stays open, for example a tmux session. In that session, in my repository, run: CLOVING_TICKET_COMMAND='["TICKET_COMMAND"]' cloving start
|
|
524
|
-
For develop-issue, also set CLOVING_CHECK_COMMAND to the checks of my repository. Give me the address of the watch page.
|
|
525
|
-
6. Make a first run with develop-prompt and a small task that I agree to. Show me the output of "cloving questions" and the diff of the branch. Do not approve or deny. I decide.
|
|
526
|
-
7. Then run my first ticket: cloving run develop-ticket --ticket TICKET_ID
|
|
527
|
-
Show me the diff again before I decide.
|
|
528
|
-
```
|
|
597
|
+
Run `cloving init` in the repository and select your agent harness. The agent runs `cloving init-prompt` to get repository facts and the setup instructions, then guides you through the remaining steps.
|
|
529
598
|
|
|
530
599
|
### Run a continuous process
|
|
531
600
|
|
|
532
601
|
```text
|
|
533
|
-
Run a continuous process with Cloving and develop
|
|
602
|
+
Run a continuous process with Cloving and develop in my repository REPOSITORY_PATH. The Cloving service runs in the terminal session SESSION_NAME. Do the issues ISSUE_LIST one at a time, in this order.
|
|
534
603
|
|
|
535
604
|
For each issue:
|
|
536
605
|
1. Read the issue. Do not change it.
|
|
537
|
-
2. Run: cloving run develop
|
|
606
|
+
2. Run: cloving run develop --ticket ISSUE_NUMBER
|
|
538
607
|
ISSUE_NUMBER is the number of the issue. Record the run ID.
|
|
539
608
|
3. Follow the run with "cloving status RUN_ID" and "cloving events RUN_ID --follow".
|
|
540
609
|
4. When the run completes, get the number of its pull request (PR_NUMBER). It is pullRequest.number of the run in http://127.0.0.1:3663/data.json, and the watch page shows it too. Then:
|
|
@@ -562,9 +631,9 @@ Do not merge a pull request yourself. Do not approve or deny for me.
|
|
|
562
631
|
Help me write a ticket for Cloving. A Claude Code worker gets the full text of the ticket and no other context. Ask me questions until each part is clear. Then write the ticket in Markdown with these parts:
|
|
563
632
|
|
|
564
633
|
# TITLE
|
|
565
|
-
One line. For develop
|
|
634
|
+
One line. For develop, it becomes the title of the pull request.
|
|
566
635
|
GitHub issue: OWNER/REPOSITORY#NUMBER
|
|
567
|
-
Only for develop
|
|
636
|
+
Only for develop. The pull request references this issue; complete work closes it after the merge.
|
|
568
637
|
## Problem
|
|
569
638
|
What is wrong now, with facts.
|
|
570
639
|
## Desired outcome
|
|
@@ -582,83 +651,47 @@ GitHub issue: OWNER/REPOSITORY#NUMBER
|
|
|
582
651
|
|
|
583
652
|
Rules:
|
|
584
653
|
- One ticket has one behavior. If the work needs more than one pull request, split the ticket.
|
|
585
|
-
- Write no secret, no private data and no local file path. For develop
|
|
654
|
+
- Write no secret, no private data and no local file path. For develop, the ticket text and the branch become public.
|
|
586
655
|
- Use one term for one thing.
|
|
587
656
|
```
|
|
588
657
|
|
|
589
|
-
### Find workflows in your chats
|
|
590
|
-
|
|
591
|
-
```text
|
|
592
|
-
Find workflows in my chats with coding agents, and write a draft Cloving workflow for one of them.
|
|
593
|
-
|
|
594
|
-
Rules:
|
|
595
|
-
- Read only the chats that I select. Ask me for the list first. Do not read other chats.
|
|
596
|
-
- Keep the chat text and private data out of the repository. Do not copy chat text, names of persons, secrets or local paths into a file of the repository. Keep your notes outside the repository.
|
|
597
|
-
|
|
598
|
-
Steps:
|
|
599
|
-
1. In the selected chats, find sequences of steps that repeat. For each sequence, list the steps, the tool of each step (for example git, a test command, gh or a model), and each decision of a person (for example "approve the diff").
|
|
600
|
-
2. Show me the list, and ask me which sequence to use.
|
|
601
|
-
3. Map each step that changes something outside the workflow to protectedEffect, with a capability and a method. Map each decision of a person to decisionGate.
|
|
602
|
-
4. Use only the capabilities that have a worker: claude (method run-turn) and github. Put each step that needs a different capability in a list of open points, not in the draft.
|
|
603
|
-
5. Write the draft in the form of workflows/develop-ticket.ts of the Cloving checkout: an exported async function with the directive "use workflow", and the step helpers from the subpaths of cloving/workflows.
|
|
604
|
-
6. Write a list of the human decisions in the draft: for each decisionGate, the question, the person who decides, and the result of each answer.
|
|
605
|
-
7. Write workflow tests with a fake step bridge, in the form of test/develop-workflow-fixture.ts.
|
|
606
|
-
8. Tell me which changes of the Cloving code the draft needs before the service can run it. The section "Develop a workflow" of the Cloving README lists them.
|
|
607
|
-
```
|
|
608
|
-
|
|
609
658
|
## Develop a workflow
|
|
610
659
|
|
|
611
|
-
`cloving start` loads workflows from
|
|
660
|
+
`cloving start` loads workflows from two folders:
|
|
612
661
|
|
|
613
|
-
- The bundled `workflows/` folder in the Cloving package. Startup compiles each TypeScript file in this folder.
|
|
614
662
|
- The repository `.cloving/workflows/` folder.
|
|
615
663
|
- The user `cloving/workflows/` folder under an absolute `XDG_CONFIG_HOME`, otherwise under `~/.config`. An unset or relative `XDG_CONFIG_HOME` uses that default.
|
|
616
664
|
|
|
617
665
|
The private setting `workflows.folder` replaces the user folder with an absolute folder path, for example a private git repository of your own workflows. Set it with `cloving config set workflows.folder <path>`. Cloving reads the folder where it is. The folder itself must not be a symbolic link; a link in the path above it is allowed. `cloving workflows list` shows its workflows with the scope `user`.
|
|
618
666
|
|
|
619
|
-
A workflow is a TypeScript file in the form of `
|
|
667
|
+
A workflow is a TypeScript file in the form of `templates/develop/develop.ts`:
|
|
620
668
|
|
|
621
669
|
- An exported async function with the directive `"use workflow"` as its first statement. The directive needs the compiler of the Workflow SDK, not only TypeScript.
|
|
622
|
-
- The
|
|
623
|
-
- The step helpers come from the subpaths of `cloving/workflows`: `protectedEffect` from `cloving/workflows/steps/protected-effect`, `
|
|
624
|
-
- `protectedEffect` asks the daemon for one effect of a capability, for example a Claude turn. `
|
|
670
|
+
- The only argument is the input of the run. The declared resolver provides `cycleId`, `repository` and the submitted fields under `input`; a ticket field becomes `{ id, text }`. With `waitForDecision`, the decision returns to the same call.
|
|
671
|
+
- The step helpers come from the subpaths of `cloving/workflows`: `protectedEffect` from `cloving/workflows/steps/protected-effect`, `waitForDecision` from `cloving/workflows/steps/wait-for-decision`, `loadCycle` from `cloving/workflows/steps/load-cycle`, `handoff` from `cloving/workflows/steps/handoff`, `waitForRun` from `cloving/workflows/steps/wait-for-run` and `runCommand` from `cloving/workflows/steps/run-command`. The type `CycleOutcome` comes from `cloving/workflows`. An import of `cloving/workflows` starts no service.
|
|
672
|
+
- `protectedEffect` asks the daemon for one effect of a capability, for example a Claude turn. `waitForDecision` opens a decision for a person and waits for the result.
|
|
625
673
|
- The function returns a `CycleOutcome`: `waiting_for_decision`, `handoff_requested` or `blocked`.
|
|
626
674
|
|
|
627
675
|
For `handoff_requested`, the daemon retains the workflow's `promotionId` in the completion event. An optional bounded `reason` records a handoff refusal while preserving the promotion. `cloving status <runId>` shows the promotion as `Promotion:` and the reason beside the outcome; JSON status includes `run.outcome.promotionId` and `run.outcome.reason`. Watch retains the promotion in the run model and completed-run details. This identifier is an opaque reference and grants no authority.
|
|
628
676
|
|
|
629
677
|
```ts
|
|
630
678
|
import type { CycleOutcome } from "cloving/workflows";
|
|
631
|
-
import {
|
|
679
|
+
import { waitForDecision } from "cloving/workflows/steps/wait-for-decision";
|
|
632
680
|
import { protectedEffect } from "cloving/workflows/steps/protected-effect";
|
|
633
681
|
|
|
634
|
-
export async function developTicket(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
readonly
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
},
|
|
641
|
-
): Promise<CycleOutcome> {
|
|
682
|
+
export async function developTicket(input: {
|
|
683
|
+
readonly cycleId: string;
|
|
684
|
+
readonly input: {
|
|
685
|
+
readonly ticket: { readonly id: string; readonly text: string };
|
|
686
|
+
};
|
|
687
|
+
}): Promise<CycleOutcome> {
|
|
642
688
|
"use workflow";
|
|
643
|
-
if (decision?.decision === "approved")
|
|
644
|
-
return {
|
|
645
|
-
kind: "handoff_requested",
|
|
646
|
-
cycleId: input.cycleId,
|
|
647
|
-
promotionId: `cloving-${input.cycleId}`,
|
|
648
|
-
};
|
|
649
|
-
if (decision !== undefined)
|
|
650
|
-
return {
|
|
651
|
-
kind: "blocked",
|
|
652
|
-
cycleId: input.cycleId,
|
|
653
|
-
reason: "The operator denied the work.",
|
|
654
|
-
evidenceId: decision.gateId,
|
|
655
|
-
};
|
|
656
689
|
const turn = await protectedEffect({
|
|
657
690
|
scope: { phase: "implement", operation: "claude-turn", round: 1 },
|
|
658
691
|
capability: "claude",
|
|
659
692
|
method: "run-turn",
|
|
660
693
|
target: input.cycleId,
|
|
661
|
-
payload: input.ticket,
|
|
694
|
+
payload: input.input.ticket.text,
|
|
662
695
|
units: 1,
|
|
663
696
|
});
|
|
664
697
|
if (turn.kind !== "completed")
|
|
@@ -668,29 +701,29 @@ export async function developTicket(
|
|
|
668
701
|
reason: "The Claude turn did not complete.",
|
|
669
702
|
evidenceId: "claude-turn",
|
|
670
703
|
};
|
|
671
|
-
const
|
|
704
|
+
const decision = await waitForDecision({
|
|
672
705
|
gateId: "review-1",
|
|
673
706
|
kind: "approval",
|
|
674
707
|
prompt: "Review the work of the Claude worker.",
|
|
675
708
|
});
|
|
676
|
-
if (
|
|
709
|
+
if (decision.decision !== "approved")
|
|
677
710
|
return {
|
|
678
711
|
kind: "blocked",
|
|
679
712
|
cycleId: input.cycleId,
|
|
680
|
-
reason: "The
|
|
713
|
+
reason: "The operator did not approve the work.",
|
|
681
714
|
evidenceId: "review-1",
|
|
682
715
|
};
|
|
683
716
|
return {
|
|
684
|
-
kind: "
|
|
717
|
+
kind: "handoff_requested",
|
|
685
718
|
cycleId: input.cycleId,
|
|
686
|
-
|
|
719
|
+
promotionId: `cloving-${input.cycleId}`,
|
|
687
720
|
};
|
|
688
721
|
}
|
|
689
722
|
```
|
|
690
723
|
|
|
691
|
-
In this example, an approval completes the run and a denial ends it. `
|
|
724
|
+
In this example, an approval completes the run and a denial ends it. A copy of `templates/develop/develop.ts` configured for person review and local-branch delivery also supports repair rounds after a denial with feedback.
|
|
692
725
|
|
|
693
|
-
|
|
726
|
+
A workflow can also wait for a decision without requesting an effect:
|
|
694
727
|
|
|
695
728
|
```ts
|
|
696
729
|
import { waitForDecision } from "cloving/workflows/steps/wait-for-decision";
|
|
@@ -710,7 +743,7 @@ export async function review(input: { cycleId: string }) {
|
|
|
710
743
|
}
|
|
711
744
|
```
|
|
712
745
|
|
|
713
|
-
`waitForDecision` accepts
|
|
746
|
+
`waitForDecision` accepts `{ gateId, kind, prompt, expiresAt? }` and returns `{ decision, answer }`. The decision is `approved`, `denied`, `answered` or `expired`. An optional `expiresAt` resumes the wait with `expired` and `answer: null`. The SDK hook survives daemon restarts and replay. Gate IDs belong to a run, so different runs can use the same gate ID. The existing questions, decision commands and binding values apply; dropping the run cancels the wait. `waitForDecision` is also exported by `cloving/workflows`.
|
|
714
747
|
|
|
715
748
|
Use `sleep({ seconds })` inside a workflow to pause between short outside-state checks. Whole seconds from 1 through 86400 are accepted; other requests reject with `invalid-sleep-seconds` before any wait. Import it from `cloving/workflows` or `cloving/workflows/steps/sleep`. It uses the SDK workflow timer and consumes no protected effect units or slots.
|
|
716
749
|
|
|
@@ -842,9 +875,24 @@ Replace that call with `mergeByPerson({ pull: pull, check: "beforeMerge" })` to
|
|
|
842
875
|
|
|
843
876
|
Both steps use the existing GitHub `merge` worker method and one protected effect unit. The candidate declaration must include the `github` capability and `methods: { "github": ["merge"] }`. The step subpaths and `cloving/workflows` export the step functions. Import the types `PullRequest`, `MergeRequest` and `MergeResult` from `cloving/workflows`. Fake scenarios give worker results in `effects["github merge"]` and person decisions in `decisions`.
|
|
844
877
|
|
|
845
|
-
|
|
878
|
+
To show a file on a pull request, for example a demo video, a worker turn writes the file into the folder in `CLOVING_ATTACHMENTS_DIRECTORY`. Each turn of a run gets the same folder, outside the work tree. Then the workflow asks for the GitHub method `attach-asset`:
|
|
879
|
+
|
|
880
|
+
```ts
|
|
881
|
+
const attached = await protectedEffect({
|
|
882
|
+
scope: { phase: "pull-request", operation: "github-attach-demo", round: 1 },
|
|
883
|
+
capability: "github",
|
|
884
|
+
method: "attach-asset",
|
|
885
|
+
target: runTarget,
|
|
886
|
+
payload: JSON.stringify({ number: pull.number, name: "demo.mp4", release: "pr-demos", comment: "Demo of the change." }),
|
|
887
|
+
units: 1,
|
|
888
|
+
});
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
The method uploads the file as an asset of the release `release`, with the asset name `pr-<number>-<name>`. Then it creates or updates one comment on the pull request with a link to the asset, so a second call adds no second comment. GitHub does not play a release video in the page. An optional `place` is `comment` (the default) or `description`. With `description`, the method writes the text and the file into the pull request body between the markers `<!-- cloving-attachment:<number>:<name> -->` and `<!-- /cloving-attachment:<number>:<name> -->`, with `gh pr edit --body-file <file> --attach <file>`. `gh` uploads the file to GitHub, and GitHub shows a video as a player. This place makes no release asset and no comment, a second call replaces the block, and it needs a `gh` version with `gh pr edit --attach`. When the release does not exist, the method creates it as a pre-release that is not the latest release. `name` is a file name with the extension `.mp4`, `.webm` or `.png`. The file must be a regular file of at most 100 MB, and a symbolic link is refused. `release` has lowercase letters, digits and hyphens, and it cannot start with `v` and a digit, so it never matches a version tag. The comment text must pass the same privacy check as issue texts. The failure reasons are `invalid-payload`, `attachment-not-available`, `attachment-too-large` and the usual GitHub reasons. The candidate declaration must include `methods: { "github": ["attach-asset"] }`.
|
|
892
|
+
|
|
893
|
+
The template tests use `fakeStepBridge` from `cloving/workflows/testing` to record effect and gate requests and supply fake results. `templates/develop/develop.test.ts` exercises the develop template through that public testing API.
|
|
846
894
|
|
|
847
|
-
Use `cloving workflows list` to inspect
|
|
895
|
+
Use `cloving workflows list` to inspect project and user workflows without a service. `--json` prints an array with `scope`, `workflowId`, `file`, `admitted`, `codes` and each valid parsed declaration. Invalid declarations have a null ID. Inspection uses the same folder admission and compiler as startup in a disposable project directory.
|
|
848
896
|
|
|
849
897
|
Put tests beside each folder workflow as `<name>.test.ts`, then run `cloving workflows test <workflow-id>`. Omit the ID to run all available project and user workflow tests. Both commands accept `--repository <directory>`. The Node test runner prints its results and supplies the exit status. Unknown IDs report `unknown-workflow`; known workflows without tests report `workflow-test-missing`. Neither needs a running service.
|
|
850
898
|
|
|
@@ -877,11 +925,11 @@ await test("develop uses the fake worker result", async () => {
|
|
|
877
925
|
});
|
|
878
926
|
```
|
|
879
927
|
|
|
880
|
-
Each scenario runs in an isolated Node process. `effects` maps `"<capability> <method>"` to result queues; `
|
|
928
|
+
Each scenario runs in an isolated Node process. `effects` maps `"<capability> <method>"` to result queues; `effects.handoff` supplies handoff results, `waits` supplies run-wait outcomes, and `decisions` supplies `{ decision, answer }` results for `waitForDecision` in call order. A missing `waitForDecision` result throws `no-scenario-result`. Sleep requests are recorded in order and complete immediately in both testing APIs, without consuming the simulated effect budget. An optional `effectLimit` simulates a budget and adds `spent` to the result. Missing effect results return `unavailable`. For tests that import the workflow directly, `using bridge = fakeStepBridge(scenario)` installs the same fake bridge until disposal and exposes `requests` and `spent`. It refuses to replace an active host bridge. The test command resolves public Cloving imports from its own package, including a global installation, without adding a package to the consumer repository.
|
|
881
929
|
|
|
882
|
-
|
|
930
|
+
There are no built-in registrations. Workflow IDs are available to project and user declarations.
|
|
883
931
|
|
|
884
|
-
For a repository or user folder workflow, use one `<name>.ts` file with one exported workflow function. Put one `<name>.declaration.json` file beside it. Function names and workflow IDs must be unique across the
|
|
932
|
+
For a repository or user folder workflow, use one `<name>.ts` file with one exported workflow function. Put one `<name>.declaration.json` file beside it. Function names and workflow IDs must be unique across the project and user folders.
|
|
885
933
|
|
|
886
934
|
Discovery considers files in the folder root and ignores `.d.ts` and `.test.ts` files. Put local TypeScript helpers in subfolders: for example, `develop.ts` can import `./develop/prompts.ts`. Helpers can import further `.ts` files through `./` paths within those subfolders and need no workflow function or declaration. Imports with parent traversal, absolute paths or a `node_modules` component are refused, as are package imports outside the public `cloving/workflows` modules.
|
|
887
935
|
|
|
@@ -916,13 +964,31 @@ The declaration has two fields: `workflow` contains the workflow declaration, an
|
|
|
916
964
|
|
|
917
965
|
The ID accepts 1–64 letters, digits or hyphens. The effect limit is 1–100; capabilities contain one or more of `claude`, `github` and `command`. The input byte limit is 1–1048576, subject to the service's own limit. Fields accept nonempty strings, integers with optional inclusive bounds, booleans, or tickets. Fields are required unless `optional` is `true`; unknown fields are rejected. Bounds apply only to integers.
|
|
918
966
|
|
|
919
|
-
A declaration can have one `"ticket": { "type": "ticket" }` field, named `ticket`. Submit its ID as a string. When it is the only required field, use `cloving run <workflow-id> --ticket 312` or `--next`. You can also use `--input ticket.json` with `{"ticket":"312"}`; include every other required field in that file. At admission, the daemon reads the configured ticket command and replaces the ID with `{ "id": "312", "text": "# ..." }` inside the workflow's `input`. `--next` selects the ID through the configured next command. Missing sources keep the `ticket-source-not-configured` and `next-source-not-configured` refusals. The `Needs #N` dependency rule and `ticket-active` refusal apply as for `develop
|
|
967
|
+
A declaration can have one `"ticket": { "type": "ticket" }` field, named `ticket`. Submit its ID as a string. When it is the only required field, use `cloving run <workflow-id> --ticket 312` or `--next`. You can also use `--input ticket.json` with `{"ticket":"312"}`; include every other required field in that file. At admission, the daemon reads the configured ticket command and replaces the ID with `{ "id": "312", "text": "# ..." }` inside the workflow's `input`. `--next` selects the ID through the configured next command. Missing sources keep the `ticket-source-not-configured` and `next-source-not-configured` refusals. The `Needs #N` dependency rule and `ticket-active` refusal apply as for `develop`. Active tickets are checked within each workflow, so different workflows can work on the same ticket. Doctor requires `ticket-command` for these declarations, and the watch form labels the field **Ticket ID**.
|
|
920
968
|
|
|
921
969
|
Optional `commands` lists distinct names from `CLOVING_COMMANDS`; executable paths and arguments belong only in the operator setting. The `command` capability requires at least one name. Registration refuses an unknown name with `command-unknown`. The execution pin retains these names with each run, and authority refuses `command` effects whose `run:<name>` method is absent from that run's pinned list with `command-not-declared`. Reordering names preserves the pin; changing names changes it. Omitted and empty lists preserve legacy pins.
|
|
922
970
|
|
|
923
|
-
Optional `commandWaits`
|
|
971
|
+
Optional `commandWaits` declares named command checks outside the ordinary effect budget. Internal `HostPorts.commandWait` methods open a wait with serialized input, request its next check and read its durable state. Authority admits checks from the pinned declaration and recorded schedule, permits one in-flight check, and schedules the next check from settlement time. Checks use the command worker and operation journal, with each process bounded by the shorter of its command time limit and the remaining wait duration. Pending output is a JSON object with `ready: false`; `ready: true` completes with the optional `value` or `null`. Command failure, interruption or malformed output fails the wait without retry. Restart preserves the deadline, schedule and results. Expiry continues while paused or stopped and requests that an in-flight check stop; dropping the run also requests a stop. Status JSON includes `commandWaits` in both run details and list summaries. Each entry shows its name, command, state, declared `maximumWaitSeconds`, `startedAt`, `deadline`, `nextCheckAt`, `checkCount`, `remainingSeconds` and terminal `reason`. Before opening, its state is `not-started`, its times are null and the full allowance remains. Active countdowns round up to whole seconds and stop at zero; early settlement freezes the remaining time. Plain status, watch cards and run details show these times beside the ordinary effect budget. Watch refreshes quiet waits between polls and retains active runs beyond one week. Wait data excludes command input and output.
|
|
972
|
+
|
|
973
|
+
The map accepts names of 1–64 ASCII letters, digits or hyphens, with entries containing exactly `command`, `maximumWaitSeconds` and `pollEverySeconds`. The command must be declared in `commands`, configured in `CLOVING_COMMANDS` and permitted by the `command` capability. Maximum wait is an integer from 60 through 2,592,000 seconds; polling interval is an integer from 60 through 86,400 seconds and cannot exceed that maximum. For example, `"commandWaits": { "team-review": { "command": "review-state", "maximumWaitSeconds": 2592000, "pollEverySeconds": 3600 } }` pins that named permission. Reordering entries preserves the execution pin; changing a name, command, duration or interval changes it and refuses incompatible resumption. Legacy runs retain their original pin without wait permission. Ordinary `runCommand` calls still spend effect units, including calls to a command named in this map. Operators must choose read-only, repeat-safe checks; command execution does not enforce read-only access.
|
|
974
|
+
|
|
975
|
+
Internal command delivery accepts the wait's absolute deadline. An attempt uses the shorter of `CLOVING_COMMAND_SECONDS` and the remaining milliseconds, refuses to spawn at or after expiry, and reports `command-wait-timeout` if it settles too late. A recorded result still replays after expiry; authority accepts readiness only when it records the result before the wait's deadline. An unfinished journaled command retains `command-interrupted` recovery. This internal cap is not exposed through ordinary workflow command requests.
|
|
976
|
+
|
|
977
|
+
Use `waitForCommand({ name, input })` for a declared command wait, imported from `cloving/workflows` or `cloving/workflows/steps/wait-for-command`:
|
|
924
978
|
|
|
925
|
-
|
|
979
|
+
```ts
|
|
980
|
+
import { waitForCommand } from "cloving/workflows/steps/wait-for-command";
|
|
981
|
+
|
|
982
|
+
const outcome = await waitForCommand({
|
|
983
|
+
name: "team-review",
|
|
984
|
+
input: { change: 42 },
|
|
985
|
+
});
|
|
986
|
+
if (outcome.kind === "ready") return outcome.value;
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
The request accepts only a declared literal `name` and JSON-serializable `input`. Extra fields, including callbacks, executables, arguments, deadlines and exemptions, are refused before dispatch. The step returns a terminal result: `{ kind: "ready", value }`, `{ kind: "timed-out", reason: "command-wait-timeout" }` or `{ kind: "failed", reason }`. Missing hosts return `kind: "unavailable"`; unknown waits and invalid requests return `kind: "refused"` with an explicit reason. Pending checks stay inside the workflow loop and never reach its caller.
|
|
990
|
+
|
|
991
|
+
The first check is immediate. Each later check is due at the previous settlement time plus the declared interval. The workflow uses durable SDK suspension between checks and wakes at the earlier of the next check and the original deadline. The deadline continues through host downtime and pauses; restart preserves it and never catches up missed checks. No check starts at or after the deadline, no automatic SDK retry repeats a failed check, and wait checks spend no ordinary effect units. Each name identifies one wait per run: identical input joins it and changed input is refused. The operator must configure a read-only check command that is safe to run again; Cloving does not enforce read-only filesystem or network access.
|
|
926
992
|
|
|
927
993
|
Use `runCommand` inside a workflow to request a named command:
|
|
928
994
|
|
|
@@ -942,7 +1008,39 @@ The daemon starts the operator command without a shell in the repository folder
|
|
|
942
1008
|
|
|
943
1009
|
The journal records a claim before starting the process. Completed effects replay their stored result after restart. A claimed effect without a result fails with `command-interrupted` after restart and never starts again, including when the earlier process may have written data. Each logical operation starts at most one command; use a new operation scope for a new invocation. The watch run page and `cloving status <run>` show each command name, state, exit status and duration.
|
|
944
1010
|
|
|
945
|
-
|
|
1011
|
+
`cloving red-green` checks the changed tests of a commit. It reads `{"head":"<full commit ID>"}` on standard input in the repository folder. The base is the merge base of that commit and `refs/remotes/origin/HEAD`. Configure `checks.redGreen` in `.cloving/config.json`:
|
|
1012
|
+
|
|
1013
|
+
```json
|
|
1014
|
+
{
|
|
1015
|
+
"version": 1,
|
|
1016
|
+
"checks": {
|
|
1017
|
+
"redGreen": {
|
|
1018
|
+
"test": ["node", "--test"],
|
|
1019
|
+
"testFiles": ["test/"],
|
|
1020
|
+
"prepare": ["npm", "ci", "--ignore-scripts"]
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
The daemon maps this object to `CLOVING_RED_GREEN`. An environment value takes priority. For direct use, set `CLOVING_RED_GREEN` to the same JSON object. `test` is an argument array. The tool appends the added or changed file paths under the `testFiles` prefixes. It excludes deleted files. `prepare` is optional and runs before each test command. Optional `assertionPattern` and `skipPattern` are regular expression strings. The defaults are `ERR_ASSERTION` and `# SKIP\b`, which match non-terminal `node --test` output.
|
|
1027
|
+
|
|
1028
|
+
Register the tool in `CLOVING_COMMANDS` with the absolute path of the installed executable, for example `{"red-green":["/opt/cloving/bin/cloving","red-green"]}`. Declare `red-green` in the workflow's `commands` list. A workflow can then call `runCommand` with `name: "red-green"` and `input: { head: commitId }`. Increase `CLOVING_COMMAND_SECONDS`, for example to `600`, to allow both preparation and test runs. This setting also bounds each preparation or test command inside the tool.
|
|
1029
|
+
|
|
1030
|
+
The red run uses a detached temporary worktree at the base with only the selected tests restored from the head. The green run uses another detached worktree at the head. Both runs use the same test paths. The tool removes each tree after the run, a command failure, a timeout, SIGINT or SIGTERM. Cleanup also runs after the operator stops the command or its process group. It preserves the repository folder's branch, index and files. The commands run as the current user.
|
|
1031
|
+
|
|
1032
|
+
The tool prints one JSON object with `verdict`, `base`, `head`, `files` and `output`. The output contains the last 16,000 characters from the command that decides the verdict. Successful preparation logs do not supply assertion or skip evidence. With no selected tests, the verdict is `no-test-change` and no command runs. Otherwise, both runs occur. The first applicable rule decides:
|
|
1033
|
+
|
|
1034
|
+
1. Preparation fails in either run: `prepare-failed`.
|
|
1035
|
+
2. Either run matches the skip pattern: `skipped-test`.
|
|
1036
|
+
3. The red run succeeds: `false-red`.
|
|
1037
|
+
4. The red run is interrupted, times out, or fails without the assertion pattern: `red-not-assertion`.
|
|
1038
|
+
5. The green run fails: `green-failed`.
|
|
1039
|
+
6. Otherwise: `accepted`.
|
|
1040
|
+
|
|
1041
|
+
Every verdict exits with status 0 so a workflow can send the result to a fix turn. Invalid input, invalid settings and git errors exit with status 1. This tool does not change the develop template or the full-suite checks on the head.
|
|
1042
|
+
|
|
1043
|
+
Optional `handoffs` lists distinct registered workflow IDs. Registration refuses unknown targets. The execution pin retains these permissions with each run: target order does not affect the pin, while adding or removing a target changes it. Omitted and empty lists keep existing pins. Stored permissions survive restart and retained workflow versions. The `idea-to-issue` template declares `develop` as its only handoff target and calls it after creating an issue. Both workflows must be copied and admitted. A refused PRD handoff adds `cloving: ready` for the queue and records the refusal in the PRD run's outcome.
|
|
946
1044
|
|
|
947
1045
|
Use `handoff` inside a workflow to submit input to a declared target:
|
|
948
1046
|
|
|
@@ -950,7 +1048,7 @@ Use `handoff` inside a workflow to submit input to a declared target:
|
|
|
950
1048
|
import { handoff } from "cloving/workflows/steps/handoff";
|
|
951
1049
|
|
|
952
1050
|
const runId = await handoff({
|
|
953
|
-
workflowId: "develop
|
|
1051
|
+
workflowId: "develop",
|
|
954
1052
|
input: { ticket: "CLV-123" },
|
|
955
1053
|
});
|
|
956
1054
|
```
|
|
@@ -979,7 +1077,7 @@ The compiled SDK step uses durable retries and its original start time, so resta
|
|
|
979
1077
|
|
|
980
1078
|
Optional `stages` contains 1–12 entries in board order. Each entry has a unique `name` (1–64 ASCII letters, digits or hyphens), a unique `label` (1–40 printable characters on one line, without outer spaces), and any combination of `operations`, `gateKinds` and `gateIds`. At least one selector array must be nonempty; the others may be omitted or empty. Operations match the `scope.operation` passed to `protectedEffect`; gate IDs match the `gateId` recorded when a gate opens. Both use 1–128 ASCII letters, digits or `._:/-`. Gate kinds are `approval` and `question`. Selectors cannot repeat within an array or belong to two stages of the same selector type within one workflow. Different selector types may share text, and different workflows may reuse IDs. Unknown fields and labels `Other`, `Done` and `Stopped` are rejected.
|
|
981
1079
|
|
|
982
|
-
For declared stages, the board and its `data.json` response use the latest committed `effect.requested` or `gate.opened` sequence, preserving that event's start time. Effect requests select by operation. Gate openings first search every stage for an exact, case-sensitive gate ID match, regardless of declaration order; without one, they fall back to the gate kind. Unmatched events and runs without a relevant event use Other. Unused valid IDs are allowed. Decisions and worker output do not advance a card; later requests or gate openings can move it back. Declared labels are followed by Other, Done and Stopped. Existing terminal retention rules take precedence. Unstaged workflows
|
|
1080
|
+
For declared stages, the board and its `data.json` response use the latest committed `effect.requested` or `gate.opened` sequence, preserving that event's start time. Effect requests select by operation. Gate openings first search every stage for an exact, case-sensitive gate ID match, regardless of declaration order; without one, they fall back to the gate kind. Unmatched events and runs without a relevant event use Other. Unused valid IDs are allowed. Decisions and worker output do not advance a card; later requests or gate openings can move it back. Declared labels are followed by Other, Done and Stopped. Existing terminal retention rules take precedence. Declared stages apply regardless of the workflow ID. Unstaged workflows keep their existing columns and placement. Declarations load at service startup; stages provide display metadata and grant no capabilities.
|
|
983
1081
|
|
|
984
1082
|
For example, a `review-flow` declaration can distinguish successive approval gates without another workflow or handoff step:
|
|
985
1083
|
|
|
@@ -1019,11 +1117,21 @@ A declared workflow can include an interval schedule:
|
|
|
1019
1117
|
|
|
1020
1118
|
The first run starts after one interval. Slots retain increasing numbers in private Cloving state (`state/schedules.json`); each submission uses the operator command ID `schedule:<workflowId>:<slot>`. Restart preserves the next boundary and retries an unacknowledged submission with its saved input and command ID. Missed intervals coalesce into the latest due slot rather than a burst of catch-up runs. Changing the interval starts a fresh interval while retaining slot numbers and any active run.
|
|
1021
1119
|
|
|
1022
|
-
An earlier scheduled run blocks later scheduled slots while queued, running, waiting for a decision or paused. Each overlap records a `schedule.skipped` event on that earlier run, with `workflowId` and `slot`, without changing its status or observation. Manual runs remain independent. The
|
|
1120
|
+
An earlier scheduled run blocks later scheduled slots while queued, running, waiting for a decision or paused. Each overlap records a `schedule.skipped` event on that earlier run, with `workflowId` and `slot`, without changing its status or observation. Manual runs remain independent. The ticket queue continues to use `CLOVING_QUEUE_SECONDS`.
|
|
1121
|
+
|
|
1122
|
+
Use `cloving schedule [--json]` to list workflow IDs, intervals, state, failure counts, slots, next run times and active runs. `cloving schedule pause <workflowId> [--json]` stops new scheduled runs without interrupting an active run or recording skips. `cloving schedule resume <workflowId> [--json]` clears the failure count and starts the next run one interval later, retaining increasing slot numbers. Repeating pause or resume leaves the current state and timing unchanged. Paused and stopped schedules survive restarts and interval changes.
|
|
1023
1123
|
|
|
1024
|
-
|
|
1124
|
+
`cloving status` shows each schedule after the queue lines, for example `Schedule review-queue: every 300 s, active, next run at 2026-10-14T12:05:00.000Z, 0 failures in a row`. Paused schedules show `paused` without a next run time; stopped schedules show `stopped`, the stop time and the failure count. The watch board shows the same information on the workflow's board and refreshes it on the next poll. Status times use ISO timestamps; watch times use the browser's local date and time.
|
|
1025
1125
|
|
|
1026
|
-
|
|
1126
|
+
Status JSON includes `schedules` entries with `workflowId`, `everySeconds`, `state`, `failuresInRow`, `nextAt` and `stoppedAt`. Times are epoch milliseconds or `null`; paused and stopped schedules have `nextAt: null`. The field is absent when no schedules are configured. A scheduler that is not running yet is shown as `schedules: { "status": "unavailable" }` and `Schedules: unavailable` in status and watch.
|
|
1127
|
+
|
|
1128
|
+
Runs admitted by a schedule show `scheduled 12` for slot 12 on the status run line, in run status, on the watch card and in the watch run detail. Their JSON summary and detail include `scheduled: { "slot": 12 }`. Manual runs have no scheduled mark.
|
|
1129
|
+
|
|
1130
|
+
Three consecutive failed scheduled runs stop a schedule. A completed run with outcome `blocked` counts as a failure; cancellation leaves the count unchanged, and any other completion clears it. With `CLOVING_NOTIFY_COMMAND` configured, each stop sends a `schedule-stopped` notification with the three failed run IDs and the resume command; its `runId` names the third failed run.
|
|
1131
|
+
|
|
1132
|
+
Schedule settings load at startup. A scheduler transport or journal failure stops scheduling and writes a diagnostic; reconcile the state and restart to retry a pending slot. Full product admission remains subject to the external verification policy.
|
|
1133
|
+
|
|
1134
|
+
Startup retains each complete compiled project under `workflow-bundles` in private daemon state, beside the generated `project` directory. Each content-addressed snapshot includes workflow sources, declarations, registration manifests, all compiler artifacts, and the installed dependency graph and Node identity. Snapshots bind to the canonical repository and survive later source edits or removal. Storage lookup validates every captured file and returns `pinned-workflow-unavailable` for missing or changed bytes; startup refuses reuse of a matching damaged snapshot without repairing it. No retained generation is deleted automatically. Before Local World starts, the daemon loads the retained generations needed by unfinished runs. Their starts, replays and continuations use the recorded bundle, including after workflow removal; new submissions use current registrations. A workflow message of a dropped run gets a done answer. No workflow code runs, the daemon records no observation, and the Local World queue stops its retries. Duplicate answers and replay preserve effect receipts and spending.
|
|
1027
1135
|
|
|
1028
1136
|
### Project and user workflows
|
|
1029
1137
|
|
|
@@ -1032,7 +1140,7 @@ At daemon startup, Cloving also checks these folders on both macOS and Linux:
|
|
|
1032
1140
|
- Project: `.cloving/workflows` under the repository selected by `cloving start --repository REPOSITORY` (the current repository by default).
|
|
1033
1141
|
- User: `$XDG_CONFIG_HOME/cloving/workflows` when `XDG_CONFIG_HOME` is absolute; otherwise `$HOME/.config/cloving/workflows`. macOS uses these same XDG rules.
|
|
1034
1142
|
|
|
1035
|
-
Missing folders are left absent. Discovery reads top-level `.ts` files, excluding `.d.ts`, and requires a matching `<name>.declaration.json`.
|
|
1143
|
+
Missing folders are left absent. Discovery reads top-level `.ts` files, excluding `.d.ts`, and requires a matching `<name>.declaration.json`. A project or user declaration wraps the workflow metadata and lists the effect methods it may request:
|
|
1036
1144
|
|
|
1037
1145
|
```json
|
|
1038
1146
|
{
|
|
@@ -1051,7 +1159,7 @@ Missing folders are left absent. Discovery reads top-level `.ts` files, excludin
|
|
|
1051
1159
|
|
|
1052
1160
|
Use one exported async workflow function with `"use workflow"` and the public `cloving/workflows` helpers. Each capability requires a nonempty list of distinct method names. Declaration, source and actual SDK compilation must pass admission before registration. Declaring a method grants no execution authority; the broker still enforces each run's capabilities and budget. Submit inputs with `cloving run project-review --input input.json`.
|
|
1053
1161
|
|
|
1054
|
-
|
|
1162
|
+
Only admitted project and user workflows are registered. A refused neighbor does not stop valid workflows from loading. `cloving status --json` exposes `workflowRefusals`; status and watch show each refusal's scope, safe file label and codes without its source text. These codes identify the failed check:
|
|
1055
1163
|
|
|
1056
1164
|
| Codes | Meaning |
|
|
1057
1165
|
| --- | --- |
|
|
@@ -1059,7 +1167,7 @@ Admitted project and user workflows appear beside the bundled registrations. A r
|
|
|
1059
1167
|
| `forbidden-import`, `missing-export` | Import outside the public helper surface, or an unavailable named export. |
|
|
1060
1168
|
| `unsupported-source`, `dynamic-effect`, `direct-effect` | Unsupported source form, a nonliteral effect request, or a direct effect outside helpers. |
|
|
1061
1169
|
| `undeclared-effect`, `effect-limit` | Requested method absent from the declaration, or statically known work exceeding the limit. |
|
|
1062
|
-
| `workflow-conflict
|
|
1170
|
+
| `workflow-conflict` | Conflicting basename, workflow ID or function name across project and user files. |
|
|
1063
1171
|
| `unsafe-workflow-path`, `workflow-read-failed`, `workflow-source-changed` | Unsafe file or folder path, unreadable input, or input changed during capture. |
|
|
1064
1172
|
| `compile-failed` | Candidate analysis or SDK compilation could not complete. |
|
|
1065
1173
|
|
|
@@ -1073,6 +1181,8 @@ The caller supplies imported symbol names, literal effect pairs (`null` represen
|
|
|
1073
1181
|
|
|
1074
1182
|
## Development of Cloving
|
|
1075
1183
|
|
|
1184
|
+
The terminal integration test uses `/usr/bin/python3` (Python 3.9 or newer) and its standard `pty` module to exercise a real terminal. No Python packages are needed.
|
|
1185
|
+
|
|
1076
1186
|
The shell tests require both zsh at `/bin/zsh` and Bash at `/bin/bash`. macOS includes them. Linux contributors and CI runners must install both before setup; on Ubuntu, install the `zsh` and `bash` system packages. The fixtures exercise zsh 5.9 and Bash 3.2 or 5.2, including their real startup files; neither shell's tests are optional. `npm run check:setup` checks that both executables run and reports a missing prerequisite before compilation.
|
|
1077
1187
|
|
|
1078
1188
|
```sh
|
|
@@ -1085,16 +1195,20 @@ npm pack --ignore-scripts
|
|
|
1085
1195
|
|
|
1086
1196
|
After a merge or branch update changes `package.json` or `package-lock.json`, rerun `npm ci --ignore-scripts` in the worktree before running checks. Copied `node_modules` can still contain the previous versions; the developer gate rejects a mismatch with the lockfile.
|
|
1087
1197
|
|
|
1088
|
-
`npm pack` prints the file name of the tarball. Install it into a separate project with `npm install --ignore-scripts --omit=dev /absolute/path/to/TARBALL`, then run `./node_modules/.bin/cloving --version` or `./node_modules/.bin/cloving start`. The package includes the emitted CLI, start program, compiler and
|
|
1198
|
+
`npm pack` prints the file name of the tarball. Install it into a separate project with `npm install --ignore-scripts --omit=dev /absolute/path/to/TARBALL`, then run `./node_modules/.bin/cloving --version` or `./node_modules/.bin/cloving start`. The package includes the emitted CLI, start program, compiler and workflow templates; startup uses the installed runtime dependencies. The package has no installation hooks. An import of `cloving/workflows` gives the step helpers `loadCycle`, `protectedEffect`, `waitForDecision`, `handoff`, `waitForRun`, `runCommand`, `sleep` and `waitForCommand`, and starts no service.
|
|
1089
1199
|
|
|
1090
1200
|
`npm run check` and `npm run test:concurrency` currently reject admission because the complete quality policy is not implemented. Setup checks are not product acceptance. State and retained releases will live outside the package installation; installing or updating the package does not activate a daemon or migrate state.
|
|
1091
1201
|
|
|
1092
|
-
Run `npm run test:scale` on an otherwise idle machine to measure authority opening at 1,000, 10,000 and 50,000 events. This command runs the benchmark alone, without coverage; the regular test suite excludes it. The fixture uses completed runs with budgets, gates and released continuations. It requires each opening to take less than two seconds and the largest opening to take less than eight times the 10,000-event opening. Replay uses the pure reducer with run-scoped projections and preserves shared effect and lease state. Large effect histories, growing gate or pending-intent state within one run, and cancelled-run recovery still require separate scaling work; this benchmark does not establish their bounds. The generated-history parity and tamper tests compare replay with the full reducer and cover every event type.
|
|
1202
|
+
Run `npm run test:scale` on an otherwise idle machine to measure authority opening at 1,000, 10,000 and 50,000 events. This command runs the benchmark alone, without coverage; the regular test suite excludes it. The fixture uses completed runs with budgets, gates and released continuations. It requires each opening to take less than two seconds and the largest opening to take less than eight times the 10,000-event opening. Replay uses the pure reducer with run-scoped projections and preserves shared effect and lease state. Large effect histories, growing gate or pending-intent state within one run, and cancelled-run recovery still require separate scaling work; this benchmark does not establish their bounds. The generated-history parity and tamper tests compare replay with the full reducer and cover every event type. The same command also measures the first status page of a service with 700 runs and 7,000 events, and requires an answer in less than 200 ms. The service keeps the projected authority state in memory, so a status request reads no projected table in full after the start.
|
|
1093
1203
|
|
|
1094
|
-
`npm run check:quality` checks the npm manifest, lock and installed versions, regenerates TypeScript output in memory, inventories first-party files, and runs strict compilation, the proposed module catalog, workflow/effect boundaries, suppression and test-integrity checks, formatting, typed lint, structural checks, clone detection and the regular local test suite. Production modules require at least 90% line, statement and function coverage and 85% branch coverage per file. Coverage uses native V8 ranges mapped to the syntax tree of the exact Node-stripped source; unimported production files fail. Class and named object types allow at most 24 callable members; interfaces allow 10. Clone checks support ordinary TypeScript and JavaScript; JSX is rejected until separately qualified. `npm run check:lint`, `npm run check:format` and `npm run test:quality` run individual development checks.
|
|
1204
|
+
`npm run check:quality` checks the npm manifest, lock and installed versions, builds the package with `npm run build`, regenerates TypeScript output in memory, inventories first-party files, and runs strict compilation, the proposed module catalog, workflow/effect boundaries, suppression and test-integrity checks, formatting, typed lint, structural checks, clone detection and the regular local test suite. Production modules require at least 90% line, statement and function coverage and 85% branch coverage per file. Coverage uses native V8 ranges mapped to the syntax tree of the exact Node-stripped source; unimported production files fail. Class and named object types allow at most 24 callable members; interfaces allow 10. Clone checks support ordinary TypeScript and JavaScript; JSX is rejected until separately qualified. `npm run check:lint`, `npm run check:format` and `npm run test:quality` run individual development checks.
|
|
1095
1205
|
|
|
1096
1206
|
The gate uses the committed `quality/test-durations.json` record to start files with unknown durations first in path order, then recorded files from longest to shortest, breaking ties by path. Stale entries have no effect. The launcher passes the ordered list directly to Node’s programmatic test runner because CLI discovery sorts positional paths. The test inventory and sorted report stay the same. Run `npm run record:test-durations` to refresh the record after adding or changing tests, then commit the JSON. This runs the regular suite with the gate's worker count, timeout settings, isolated environment and V8 coverage, sums each file's top-level test and suite durations in seconds, and writes entries in path order after a successful complete run. Nested tests are not counted twice. Temporary coverage stays outside the repository and is removed afterward. The command accepts the same concurrency and time-factor settings as the gate.
|
|
1097
1207
|
|
|
1208
|
+
CI runs three duration-balanced shards for macOS and each Linux Node version on each pull request and each push to `main`. Only shard 1 runs the static checks. Each shard builds the package before testing, the same as the local gate, so runtime declarations are available independently of other test files. On a pull request, each shard exports raw production coverage, and a final job checks their joined coverage. A push to `main` runs the same shards with `CLOVING_TEST_COVERAGE=off`, so its test processes collect no coverage, and it skips the coverage job. The required checks remain `quality` and `quality_linux`. Without a shard setting, the local gate runs all checks and coverage as before and ignores `CLOVING_TEST_COVERAGE`.
|
|
1209
|
+
|
|
1210
|
+
A version tag runs no tests, because the `main` CI already tested its commit. The `release_check` job requires that the tagged commit is on `main`, and it waits up to 80 minutes for the `main` CI run of the same commit to pass. Then the publish job builds the package, publishes it and creates the GitHub release.
|
|
1211
|
+
|
|
1098
1212
|
The quality report includes elapsed time and the effective limit in milliseconds for each bounded command: npm inventory, clone detection, tests and coverage conversion. Commands using more than 80 percent of their limit produce a warning in the JSON report and on stderr after the report. Failed checks print the collected timings and warnings with the original error and a failing exit status. Warnings preserve a passing result. If your change made the check slower, address the warning in the same ticket.
|
|
1099
1213
|
|
|
1100
1214
|
The watch scrolling tests launch an isolated headless Chrome process at desktop and phone widths. They require Chrome on the test machine. Run them with `node --test test/watch-scrolling.test.ts`. The fixture serves bundled Preact and board data over loopback and blocks external page resources.
|
|
@@ -1109,13 +1223,13 @@ done
|
|
|
1109
1223
|
|
|
1110
1224
|
The expansion helper waits for two animation frames before horizontal input. Resolving in the first callback can send the gesture before the widened Done column renders, leaving the board at its old horizontal scroll limit even after scrolling settles. The regression delays that rendering pass with `testMilliseconds(250)` and keeps the full card visibility assertion. A failure reports the card, column and board rectangles, both scroll positions and the viewport; compare the card's right edge with the board's right edge to distinguish horizontal clipping from an incomplete vertical scroll.
|
|
1111
1225
|
|
|
1112
|
-
Before a ticket report, commit your work and run `npm run check:clean`. It refuses uncommitted changes, archives the committed tree of `HEAD` into a temporary directory, copies the worktree's `node_modules`, and runs `node tools/check-quality.ts` there with the same environment and exit code. Ignored
|
|
1226
|
+
Before a ticket report, commit your work and run `npm run check:clean`. It refuses uncommitted changes, archives the committed tree of `HEAD` into a temporary directory, copies the worktree's `node_modules`, and runs `node tools/check-quality.ts` there with the same environment and exit code. Ignored files are absent, so tests that rely on stale local files fail. The gate builds `dist/` again from the committed sources. The temporary copy is removed after success, failure or SIGINT/SIGTERM interruption.
|
|
1113
1227
|
|
|
1114
|
-
After merging dependency changes, run `npm ci --ignore-scripts` in the worktree before checking it. Copied dependencies can belong to an earlier lockfile; `check:clean` copies them unchanged. An `installed-lock-mismatch` requires refreshing that installation and rerunning the checks.
|
|
1228
|
+
After merging dependency changes, run `npm ci --ignore-scripts` in the worktree before checking it. Copied dependencies can belong to an earlier lockfile; `check:clean` copies them unchanged. An `installed-lock-mismatch` requires refreshing that installation and rerunning the checks.
|
|
1115
1229
|
|
|
1116
|
-
Set `CLOVING_CHECK_TIME_FACTOR` to a whole number from 1 to
|
|
1230
|
+
Set `CLOVING_CHECK_TIME_FACTOR` to a whole number from 1 to 9 (default 1) to multiply the developer gate test and coverage command time limits, the inner hook check limit (15 seconds by default), and the installed hook limit (30 seconds by default). With factor 3, the hook limits are 45 and 90 seconds, respectively.
|
|
1117
1231
|
|
|
1118
|
-
Set `CLOVING_TEST_CONCURRENCY` to a whole number from 1 to
|
|
1232
|
+
Set `CLOVING_TEST_CONCURRENCY` to a whole number from 1 to 16 to override the developer gate's test worker count. Without the setting, the gate uses one fewer worker than the available cores, with a minimum of 2 and a maximum of 4. macOS CI sets it to 3 and Ubuntu CI sets it to 4. CI also sets `NODE_OPTIONS` to `--max-old-space-size=4096`, because the gate process needs about 2 GB of heap, and the hosted macOS runner gives only about 2 GB by default. Fork pull requests and other events use GitHub-hosted runners. Pushes start CI only for `main` and `v*` tags. A new push to a pull request cancels the older CI runs of that pull request, and a new manual run cancels the older manual runs of its branch; runs of `main` and of tags are never cancelled. Invalid values fail with an error.
|
|
1119
1233
|
|
|
1120
1234
|
Tests that stop a child process should await `stopChild` from `test/stop-child.ts`. Use `stopChildGroup` for a detached process group, including descendants whose leader has exited. Both helpers send `SIGTERM`, wait up to five seconds times `CLOVING_CHECK_TIME_FACTOR` for exit, then escalate to `SIGKILL`. When a test requires a hard crash or an unresponsive child, start that child with `NODE_V8_COVERAGE` omitted so a kill cannot interrupt its coverage recording. Keep coverage enabled for ordinary child runs and recovery runs.
|
|
1121
1235
|
|