@mingchuno/agent-workflows 0.1.0 → 0.2.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 +32 -6
- package/dist/src/adapters/agents.js +6 -3
- package/dist/src/adapters/hosting.js +16 -10
- package/dist/src/adapters/sdk-protocol.d.ts +3 -3
- package/dist/src/adapters/sdk-protocol.js +9 -7
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +40 -19
- package/dist/src/config.d.ts +22 -22
- package/dist/src/config.js +31 -26
- package/dist/src/defaults.d.ts +2 -0
- package/dist/src/defaults.js +2 -0
- package/dist/src/domain.d.ts +24 -4
- package/dist/src/domain.js +10 -3
- package/dist/src/evidence.d.ts +54 -0
- package/dist/src/evidence.js +214 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/invocation.d.ts +24 -0
- package/dist/src/invocation.js +163 -0
- package/dist/src/operations.d.ts +7 -2
- package/dist/src/operations.js +76 -134
- package/dist/src/prompts.d.ts +28 -0
- package/dist/src/prompts.js +63 -0
- package/dist/src/recovery.d.ts +19 -0
- package/dist/src/recovery.js +99 -0
- package/dist/src/runner.d.ts +5 -0
- package/dist/src/runner.js +145 -18
- package/dist/src/runtime/process.d.ts +2 -0
- package/dist/src/runtime/process.js +41 -12
- package/dist/src/store.d.ts +21 -2
- package/dist/src/store.js +122 -1
- package/dist/src/tui/actions.d.ts +16 -0
- package/dist/src/tui/actions.js +23 -0
- package/dist/src/tui/constants.d.ts +6 -0
- package/dist/src/tui/constants.js +3 -0
- package/dist/src/{tui-data.d.ts → tui/data.d.ts} +8 -6
- package/dist/src/tui/data.js +141 -0
- package/dist/src/tui/dialogs.d.ts +17 -0
- package/dist/src/tui/dialogs.js +149 -0
- package/dist/src/tui/format.d.ts +7 -0
- package/dist/src/tui/format.js +62 -0
- package/dist/src/tui/index.d.ts +2 -0
- package/dist/src/tui/index.js +1 -0
- package/dist/src/tui/layout.d.ts +25 -0
- package/dist/src/tui/layout.js +36 -0
- package/dist/src/tui/log-file.d.ts +26 -0
- package/dist/src/tui/log-file.js +156 -0
- package/dist/src/tui/log.d.ts +11 -0
- package/dist/src/tui/log.js +90 -0
- package/dist/src/tui/monitor.d.ts +8 -0
- package/dist/src/tui/monitor.js +222 -0
- package/dist/src/tui/text.d.ts +3 -0
- package/dist/src/tui/text.js +10 -0
- package/dist/src/tui/use-log-controller.d.ts +27 -0
- package/dist/src/tui/use-log-controller.js +192 -0
- package/dist/src/tui/views.d.ts +17 -0
- package/dist/src/tui/views.js +97 -0
- package/docs/api.md +119 -6
- package/docs/architecture.md +21 -4
- package/docs/configuration.md +137 -5
- package/docs/database.md +7 -0
- package/docs/operations.md +117 -2
- package/docs/providers.md +58 -2
- package/docs/releases.md +34 -79
- package/examples/config.ts +2 -2
- package/package.json +4 -2
- package/dist/src/tui-data.js +0 -89
- package/dist/src/tui.d.ts +0 -5
- package/dist/src/tui.js +0 -69
- package/docs/acceptance.md +0 -35
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { recoveryUnavailable } from "../recovery.js";
|
|
4
|
+
import { cells, colorFor, duration, elapsedRun, executionDuration, wrapLines, } from "./format.js";
|
|
5
|
+
function stepText(event) {
|
|
6
|
+
if (!event)
|
|
7
|
+
return "No steps recorded";
|
|
8
|
+
const payload = event.payload;
|
|
9
|
+
return `${payload.name ?? "step"} · ${payload.status ?? "recorded"} · attempt ${payload.attempt ?? "—"}`;
|
|
10
|
+
}
|
|
11
|
+
export function summaryLines(run, now, event) {
|
|
12
|
+
return [
|
|
13
|
+
`#${run.issue.number} ${run.issue.title}`,
|
|
14
|
+
`${run.outcome.toUpperCase()} · ${run.phase}`,
|
|
15
|
+
`Attempt ${run.attempt} · Execution ${executionDuration(run.executions?.at(-1), now)}`,
|
|
16
|
+
"",
|
|
17
|
+
"PROGRESS",
|
|
18
|
+
stepText(event),
|
|
19
|
+
"",
|
|
20
|
+
"VALIDATION",
|
|
21
|
+
...(run.validation?.map((check) => `${check.command}: exit ${check.exitCode}`) ?? ["No checks recorded"]),
|
|
22
|
+
"",
|
|
23
|
+
"NEXT ACTION",
|
|
24
|
+
...(run.error
|
|
25
|
+
? [
|
|
26
|
+
`Error: ${run.error.split("\n")[0]}`,
|
|
27
|
+
"Enter details for the full error and recovery evidence",
|
|
28
|
+
]
|
|
29
|
+
: [
|
|
30
|
+
run.outcome === "running"
|
|
31
|
+
? "Workflow is running"
|
|
32
|
+
: run.outcome === "queued"
|
|
33
|
+
? "Waiting for runner and project intake"
|
|
34
|
+
: ["failed", "blocked", "cancelled"].includes(run.outcome)
|
|
35
|
+
? "Inspect details before retry or recovery"
|
|
36
|
+
: "Workflow finished; inspect the outcome",
|
|
37
|
+
]),
|
|
38
|
+
...(run.change ? [`Change request: ${run.change.url}`] : []),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
export function detailLines(run, sessions, now, recoveryReason = recoveryUnavailable(run)) {
|
|
42
|
+
return [
|
|
43
|
+
`#${run.issue.number} ${run.issue.title}`,
|
|
44
|
+
`${run.outcome} · ${run.phase} · attempt ${run.attempt}`,
|
|
45
|
+
`Run: ${run.id}`,
|
|
46
|
+
`Branch: ${run.branch}`,
|
|
47
|
+
`Issue: ${run.issue.url}`,
|
|
48
|
+
`Total elapsed: ${elapsedRun(run, now)}`,
|
|
49
|
+
...(run.executions ?? []).flatMap((execution, index) => [
|
|
50
|
+
"",
|
|
51
|
+
`EXECUTION ${index + 1}: ${execution.id}`,
|
|
52
|
+
`${execution.outcome} · ${execution.phase} · duration ${executionDuration(execution, now)}`,
|
|
53
|
+
`Queue wait: ${duration(execution.createdAt, execution.startedAt ?? execution.finishedAt, now)}`,
|
|
54
|
+
`Started: ${execution.startedAt ?? "Not started"} · Finished: ${execution.finishedAt ?? "—"}`,
|
|
55
|
+
...(execution.recoveryOf
|
|
56
|
+
? [
|
|
57
|
+
`Recovered from: ${execution.recoveryOf}`,
|
|
58
|
+
`Reused: ${execution.reusedSteps?.join(", ") ?? "—"}`,
|
|
59
|
+
]
|
|
60
|
+
: []),
|
|
61
|
+
]),
|
|
62
|
+
"",
|
|
63
|
+
"RECOVERY",
|
|
64
|
+
recoveryReason ?? "Eligible for admission; runner checks still required",
|
|
65
|
+
"",
|
|
66
|
+
"ERROR",
|
|
67
|
+
run.error ?? "None",
|
|
68
|
+
"",
|
|
69
|
+
"VALIDATION",
|
|
70
|
+
...(run.validation?.flatMap((check) => [
|
|
71
|
+
`${check.command} ${check.args.join(" ")} · exit ${check.exitCode} · ${duration(check.startedAt, check.finishedAt, now)}`,
|
|
72
|
+
`Log: ${check.log}`,
|
|
73
|
+
]) ?? ["No checks recorded"]),
|
|
74
|
+
"",
|
|
75
|
+
"AGENT SESSIONS",
|
|
76
|
+
...sessions.flatMap((session) => [
|
|
77
|
+
`${session.step} · invocation ${session.attempt} · ${session.outcome}`,
|
|
78
|
+
`Session: ${session.sessionId ?? session.sessionState}`,
|
|
79
|
+
`Duration: ${duration(session.startedAt, session.finishedAt, now)}`,
|
|
80
|
+
`Requested: ${JSON.stringify(session.requested)}`,
|
|
81
|
+
`Effective: ${JSON.stringify(session.effective)}`,
|
|
82
|
+
`Log: ${session.log}`,
|
|
83
|
+
"",
|
|
84
|
+
]),
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
export function Lines({ lines, width, height, offset = 0, }) {
|
|
88
|
+
const wrapped = wrapLines(lines, width);
|
|
89
|
+
const start = Math.min(offset, Math.max(0, wrapped.length - height));
|
|
90
|
+
return (_jsx(Box, { flexDirection: "column", width: width, height: height, overflow: "hidden", children: wrapped.slice(start, start + height).map((line, index) => (_jsx(Box, { height: 1, flexShrink: 0, children: _jsx(Text, { wrap: "truncate", children: line || " " }) }, `${start + index}`))) }));
|
|
91
|
+
}
|
|
92
|
+
export function RunList({ runs, selected, width, height, now, }) {
|
|
93
|
+
const count = Math.max(1, Math.floor(height / 3));
|
|
94
|
+
const current = Math.max(0, runs.findIndex((run) => run.id === selected));
|
|
95
|
+
const start = Math.max(0, Math.min(current - Math.floor(count / 2), runs.length - count));
|
|
96
|
+
return (_jsx(Box, { flexDirection: "column", height: height, overflow: "hidden", children: runs.length ? (runs.slice(start, start + count).map((run) => (_jsxs(Box, { flexDirection: "column", height: 3, children: [_jsx(Text, { inverse: run.id === selected, bold: run.id === selected, wrap: "truncate", children: cells(`${run.id === selected ? ">" : " "} #${run.issue.number} ${run.issue.title}`, width) }), _jsx(Text, { color: colorFor(run.outcome), wrap: "truncate", children: cells(` ${run.outcome} · ${run.phase} · ${executionDuration(run.executions?.at(-1), now)}`, width) }), _jsx(Text, { dimColor: true, children: cells(` attempt ${run.attempt}`, width) })] }, run.id)))) : (_jsx(Text, { children: "No runs yet. Waiting for eligible issues." })) }));
|
|
97
|
+
}
|
package/docs/api.md
CHANGED
|
@@ -4,9 +4,9 @@ Exports are in `src/index.ts`; the built package resolves to `dist/src/index.js`
|
|
|
4
4
|
|
|
5
5
|
## Runner and controls
|
|
6
6
|
|
|
7
|
-
`new Runner({config,databaseUrl,hosting,agents,workspace?,workflow?,workflowVersion?})` injects hosting/agent adapters and optionally a workspace strategy or workflow. `hosting(project)` returns a host-qualified adapter. `agents` maps provider names to adapters. The default workspace uses the existing checkout. One DBOS runtime runs per Node process; one runner owns each configuration and checkout.
|
|
7
|
+
`new Runner({config,databaseUrl,hosting,agents,workspace?,workflow?,workflowVersion?,promptBaseDirectory?})` injects hosting/agent adapters and optionally a workspace strategy or workflow. `hosting(project)` returns a host-qualified adapter. `agents` maps provider names to adapters. The default workspace uses the existing checkout. One DBOS runtime runs per Node process; one runner owns each configuration and checkout.
|
|
8
8
|
|
|
9
|
-
`start()` validates registration, acquires ownership, launches DBOS, registers concurrency-one project queues, and starts polling. `poll(projectId?)` performs an immediate scan. `pause(projectId)` stops new starts while active work continues. `resume(projectId)` refuses blocked checkouts. `stop(runId)` waits for the active invocation/process to end, or cancels queued work. `retry(runId)` requires a terminal failed/blocked/cancelled run and a clean checkout, then returns a new linked run ID. `shutdown()` stops intake, cancels and awaits active work, closes DBOS and releases ownership.
|
|
9
|
+
`start()` validates registration, acquires ownership, launches DBOS, registers concurrency-one project queues, and starts polling. `poll(projectId?)` performs an immediate scan. `pause(projectId)` stops new starts while active work continues. `resume(projectId)` refuses blocked checkouts. `stop(runId)` waits for the active invocation/process to end, or cancels queued work. `retry(runId)` requires a terminal failed/blocked/cancelled run and a clean checkout, then returns a new linked run ID. `recover(runId)` returns a new execution ID for publication recovery of the same run. `shutdown()` stops intake, cancels and awaits active work, closes DBOS and releases ownership.
|
|
10
10
|
|
|
11
11
|
Use `try/finally` to call `shutdown()`, including failed startup. A custom `workflowVersion` must change when its durable step order changes; finish existing work before replacing an incompatible version.
|
|
12
12
|
|
|
@@ -36,17 +36,110 @@ commit together; failure preserves the blocked state.
|
|
|
36
36
|
| `publishReview()` | Reject stale head; reconcile review marker; map valid added-line findings |
|
|
37
37
|
| `complete(outcome?)` | Require clean checkout and persist terminal outcome |
|
|
38
38
|
| `step(name, operation)` | Custom durable operation receiving current `RunRecord` |
|
|
39
|
-
| `invoke(name, stage,
|
|
39
|
+
| `invoke(name, stage, task)` | Custom agentic step with profile resolution and session history |
|
|
40
|
+
|
|
41
|
+
`task` separates `defaultPrompt` from an optional `context(run)` supplier.
|
|
42
|
+
Optional `readOnly`, Zod `outputContract`, and captured `evidence` control runtime
|
|
43
|
+
checks. Stage overrides replace only `defaultPrompt`. Custom stages have no
|
|
44
|
+
inferred built-in default; resolve file-based custom stages before invocation
|
|
45
|
+
with `resolveStagePrompt(stage, defaultPrompt, baseDirectory)` if they must be
|
|
46
|
+
frozen alongside startup configuration. The runner resolves built-in prompt files
|
|
47
|
+
at construction using `promptBaseDirectory`.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
await operations.invoke("report", stage, {
|
|
51
|
+
defaultPrompt: "Summarize the recorded validation.",
|
|
52
|
+
context: (run) => JSON.stringify(run.validation ?? []),
|
|
53
|
+
readOnly: true,
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
An output contract enables strict response validation and one format correction
|
|
58
|
+
within the original deadline. Both attempts retain separate invocation/session
|
|
59
|
+
records under the same durable step. The returned string is validated JSON when
|
|
60
|
+
a contract is supplied. Codex output contracts must use its supported JSON-schema
|
|
61
|
+
subset: every property is required; use nullable defaults for optional locations.
|
|
62
|
+
Built-in review parsing accepts omitted locations and normalizes them to `null`. Interrupted calls are never automatically replayed.
|
|
40
63
|
|
|
41
64
|
Put side effects inside `step`; custom effects must be idempotent or reconcile their own ambiguous results. A DBOS checkpoint does not snapshot a checkout. Returning from a custom workflow without calling a terminal operation is invalid. [Reporting workflow](../examples/custom-workflow.ts) inserts a validation report without editing provider code.
|
|
42
65
|
|
|
66
|
+
## DBOS SDK direct usage
|
|
67
|
+
|
|
68
|
+
A custom `workflow(operations)` runs inside the runner's registered DBOS workflow.
|
|
69
|
+
It can mix predefined operations with direct SDK calls; no additional workflow
|
|
70
|
+
registration or DBOS runtime is needed. In a consuming application, declare
|
|
71
|
+
`@dbos-inc/dbos-sdk` as a direct dependency compatible with this package's SDK
|
|
72
|
+
version, and ensure both resolve to the same runtime instance.
|
|
73
|
+
|
|
74
|
+
This example adds a checkpointed health check against a local service before the
|
|
75
|
+
standard workflow. The service must expose `/health` on port 8080.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
79
|
+
import {
|
|
80
|
+
defaultWorkflow,
|
|
81
|
+
type Operations,
|
|
82
|
+
} from "@mingchuno/agent-workflows";
|
|
83
|
+
|
|
84
|
+
export async function customWorkflow(operations: Operations): Promise<void> {
|
|
85
|
+
await DBOS.runStep(
|
|
86
|
+
async () => {
|
|
87
|
+
const signal = AbortSignal.any([
|
|
88
|
+
operations.dependencies.signal,
|
|
89
|
+
AbortSignal.timeout(5_000),
|
|
90
|
+
]);
|
|
91
|
+
signal.throwIfAborted();
|
|
92
|
+
const response = await fetch("http://127.0.0.1:8080/health", { signal });
|
|
93
|
+
await response.body?.cancel();
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(`Local service returned ${response.status}`);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{ name: "check-local-service", retriesAllowed: false },
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
await defaultWorkflow(operations);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
In the [runner example](../examples/run.ts), import this function and replace its
|
|
106
|
+
`workflow` and `workflowVersion` options:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
workflow: customWorkflow,
|
|
110
|
+
workflowVersion: "local-health-v1",
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The successful check is checkpointed and skipped during recovery; it is not a
|
|
114
|
+
fresh health check on every restart. `defaultWorkflow` supplies the normal coding
|
|
115
|
+
operations and terminal outcome. See the [DBOS step API](https://docs.dbos.dev/typescript/reference/workflows-steps).
|
|
116
|
+
|
|
117
|
+
Caveats:
|
|
118
|
+
|
|
119
|
+
- `operations.step(name, callback)` adds cancellation and checkout checks, phase
|
|
120
|
+
updates, step events and error redaction around `DBOS.runStep`. Prefer it for
|
|
121
|
+
custom application operations. Raw steps retain DBOS history but bypass those
|
|
122
|
+
additions; pass the runner's abort signal to cancellable work, as above.
|
|
123
|
+
- Keep I/O, time reads and randomness inside durable steps. Call orchestration
|
|
124
|
+
APIs such as `DBOS.sleepms` at workflow level. Do not wrap predefined operations
|
|
125
|
+
or the whole workflow inside `runStep`; each operation owns its checkpoints.
|
|
126
|
+
- Disabling retries does not make external writes exactly-once. A crash after an
|
|
127
|
+
effect but before checkpointing can repeat it. Use stable idempotency keys or
|
|
128
|
+
reconcile ambiguous results. DBOS does not snapshot or restore checkout files.
|
|
129
|
+
- Finish custom paths with a terminal operation such as `operations.complete()`;
|
|
130
|
+
returning while a run remains queued/running is invalid.
|
|
131
|
+
- Change `workflowVersion` when durable step order changes, and finish or
|
|
132
|
+
explicitly resolve pending runs before deploying an incompatible workflow.
|
|
133
|
+
- Let `Runner` own `DBOS.setConfig`, `launch` and `shutdown`. Direct SDK use inside
|
|
134
|
+
a workflow does not grant another runtime or bypass checkout ownership rules.
|
|
135
|
+
|
|
43
136
|
## Extension contracts
|
|
44
137
|
|
|
45
138
|
`Workspace` separates `check`, `prepare`, `inspect`, `verify`, `commit`, `push` and `release`. `Snapshot` contains branch/head, changed paths, diff and a content fingerprint. Never implement release by discarding files. A future isolated workspace implementation can replace this interface without changing workflow composition.
|
|
46
139
|
|
|
47
140
|
`prepare`, `commit` and `push` receive an optional final `AbortSignal`. Custom workspaces must stop their subprocesses before settling a cancelled operation. The existing-checkout strategy journals Git processes under the Git directory; ownership acquisition rejects surviving process groups after a runner crash.
|
|
48
141
|
|
|
49
|
-
`AgentAdapter.validate(profile)` returns observable effective settings. `invoke(input)` receives working directory, prompt
|
|
142
|
+
`AgentAdapter.validate(profile)` returns observable effective settings. `invoke(input)` receives working directory, prompt, optional application-owned `outputSchema`, read-only intent, abort signal, stage `timeoutMs` and session/event callbacks. The abort signal also covers cancellation and time spent validating the profile. Call `session(id)` immediately when available. Await event persistence; invocation must not settle until its work has stopped. SDK adapters enforce process-group lifecycle; custom adapters must uphold the same contract. `processFile` is available for controlled subprocess ownership.
|
|
50
143
|
|
|
51
144
|
`HostingAdapter` provides issue pagination/revalidation, instance-qualified `identity`, change-request lookup/create, remote head, and idempotent review publication. `preflight` is optional. Reconciliation keys must be stable across response loss; providers must never infer successful publication from agent prose.
|
|
52
145
|
|
|
@@ -59,6 +152,26 @@ and process safety check, which runs under the project lock for new admissions
|
|
|
59
152
|
only. This callback must not mutate Store records. Operator tools should use
|
|
60
153
|
`retry` commands or `Runner.retry`, preserving those safety checks.
|
|
61
154
|
|
|
62
|
-
Invocation records include project/run IDs, stable DBOS step ID and name, invocation ID, attempt, timestamps, requested/effective profile, provider, prompt/
|
|
155
|
+
Invocation records include project/run IDs, stable DBOS step ID and name, invocation ID, attempt, timestamps, requested/effective profile, provider, effective task prompt/source/hash, output-contract and evidence identities, artifact path and session state (`pending`, `available`, `unavailable`). Repeated custom steps retain separate invocations. A retry has a separate run record linked to its predecessor.
|
|
156
|
+
|
|
157
|
+
`request(kind,target)` queues the same `pause`, `resume`, `stop`, `retry`, or `recover` commands used by the CLI/TUI; `commands()` reports pending/success/failure. A runner must be active to execute them. `finishCommand` and record-writing methods support adapters and custom workflows; operator tools should prefer commands over direct mutation.
|
|
158
|
+
|
|
159
|
+
## Publication recovery
|
|
160
|
+
|
|
161
|
+
`Runner.recover(runId, commandId?)` supports failed publication steps in the
|
|
162
|
+
default workflow. It validates the source execution, checkout, configuration,
|
|
163
|
+
artifacts and remote state. `Store.admitRecovery` commits intent and its event
|
|
164
|
+
under the same project lock as retry admission; its safety callback must not
|
|
165
|
+
mutate Store records. Operator tools should use the runner or queued commands.
|
|
166
|
+
|
|
167
|
+
`RunRecord.executions` contains the initial execution and recovery executions,
|
|
168
|
+
including DBOS IDs, source execution, restart step, reused steps, configuration
|
|
169
|
+
fingerprint and outcomes. Run IDs remain stable for invocations and publication
|
|
170
|
+
markers. `Store.recoveryPlan(runId)` reports persisted eligibility and its reason;
|
|
171
|
+
live safety checks happen at admission and execution. Runs without execution
|
|
172
|
+
metadata remain readable and retryable, but cannot be recovered.
|
|
63
173
|
|
|
64
|
-
|
|
174
|
+
Recovery uses DBOS forks, retaining the original workflow input and checkpoint
|
|
175
|
+
prefix. The accepted command ID is the fork ID: dispatch adopts an existing fork
|
|
176
|
+
after an uncertain response or crash. Copied start gates do not replace live
|
|
177
|
+
checks in the first non-replayed operation. Successful prefixes cannot rerun.
|
package/docs/architecture.md
CHANGED
|
@@ -5,20 +5,37 @@ DBOS owns workflow execution, durable steps and concurrency-one project queues.
|
|
|
5
5
|
- `config.ts` / `domain.ts`: validated configuration, vocabulary and adapter contracts.
|
|
6
6
|
- `runner.ts`: local ownership, intake/deduplication, DBOS lifecycle and operator controls.
|
|
7
7
|
- `operations.ts`: reusable durable coding operations and the default workflow.
|
|
8
|
+
- `prompts.ts` / `invocation.ts`: resolved task text, output contracts and bounded format correction.
|
|
9
|
+
- `evidence.ts`: indexed, hashed change artifacts and capture limits.
|
|
10
|
+
- `recovery.ts`: publication recovery eligibility, input fingerprints and live safety checks.
|
|
8
11
|
- `workspace.ts`: existing-checkout Git operations and change verification.
|
|
9
12
|
- `store.ts`: typed Drizzle queries for run, invocation, project, command and event records; `db/schema.ts` and `drizzle/` own the application schema and migrations.
|
|
10
13
|
- `adapters/`: provider clients and isolated SDK workers.
|
|
11
14
|
- `runtime/`: process groups, ownership journals and redacted logging.
|
|
12
|
-
- `cli.ts` / `tui
|
|
15
|
+
- `cli.ts` / `tui/`: shared command/query interfaces.
|
|
13
16
|
|
|
14
|
-
Application records live in `agent_workflows`; DBOS maintains its own execution schema in the same PostgreSQL database. Large streamed agent/validation logs live under the configured state directory, referenced by records.
|
|
17
|
+
Application records live in `agent_workflows`; DBOS maintains its own execution schema in the same PostgreSQL database. Large streamed agent/validation logs live under the configured state directory, referenced by records. Interrupted or failed agent calls are never automatically retried. A returned response that fails its output contract may receive one fresh inspection-only format-correction attempt within the same stage deadline. Publication retries and explicit recovery reconcile external state first. Clean terminal state and terminal workflow outcome are deliberately separate.
|
|
15
18
|
|
|
16
19
|
Node/PostgreSQL/Git are the only runtime infrastructure; providers require their normal local authentication. Zod, Commander, Ink/React, Drizzle/node-postgres, Pino, Octokit and Gitbeaker handle standard infrastructure. Drizzle ORM and Codex SDK are Apache-2.0; the other listed runtime libraries and Copilot SDK are MIT-licensed. Exact dependency versions are pinned by the lockfile. No custom HTTP client, CLI parser or terminal renderer is introduced.
|
|
17
20
|
|
|
18
21
|
The test boundary is the public runner/workflow API using real PostgreSQL, real temporary Git repositories and controlled adapters. Separate adapter contracts exercise SDK argument/event mapping and HTTP behavior. Process-level recovery tests terminate a runner after external effects and restart it against the same state. Runtime/provider smoke calls are intentionally separate from deterministic acceptance tests.
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
The runner supports existing checkouts only. Higher per-project concurrency requires isolated workspaces and lifecycle design; changing the DBOS queue limit alone is unsafe.
|
|
21
24
|
|
|
22
25
|
## Package boundary
|
|
23
26
|
|
|
24
|
-
Keep one package while the SDK, CLI and TUI share a runtime, schema and release cycle. `src/adapters`, `src/runtime` and `src/
|
|
27
|
+
Keep one package while the SDK, CLI and TUI share a runtime, schema and release cycle. `src/adapters`, `src/runtime`, `src/db` and `src/tui` provide internal boundaries without workspace packages. Split into a monorepo when a separately deployed app or independently versioned package needs its own dependencies and build. `pnpm-workspace.yaml` currently configures installation policy only.
|
|
28
|
+
|
|
29
|
+
## Run and execution identity
|
|
30
|
+
|
|
31
|
+
A run owns the branch, commit and publication markers. Its initial DBOS execution
|
|
32
|
+
uses the run ID; publication recovery forks the failed execution at its failed
|
|
33
|
+
step under a new execution ID, preserving completed checkpoints and the original
|
|
34
|
+
run input. Execution history stays in the run record. Fresh retry creates a new
|
|
35
|
+
run and branch.
|
|
36
|
+
|
|
37
|
+
Recovery admission and retry share a project lock. Admission persists the fork ID
|
|
38
|
+
before dispatch so a restarted runner can adopt an existing fork. Recovery gates
|
|
39
|
+
run inside the first operation that actually executes, avoiding copied pause and
|
|
40
|
+
safety decisions. Recovery is limited to the default workflow's publication
|
|
41
|
+
steps; interrupted agents still require manual inspection.
|
package/docs/configuration.md
CHANGED
|
@@ -6,7 +6,7 @@ The CLI reads `agent-workflows.json`, or `--config PATH`. Unknown properties are
|
|
|
6
6
|
| ---------------- | --------------------------------------------------------------------------------------------------------- |
|
|
7
7
|
| `id` | Required stable letters/digits/underscore/hyphen identity; scopes records and queues |
|
|
8
8
|
| `databaseUrlEnv` | `AGENT_WORKFLOWS_DATABASE_URL`; environment variable containing a PostgreSQL connection URL with username |
|
|
9
|
-
| `stateDirectory` | `.agent-workflows`;
|
|
9
|
+
| `stateDirectory` | `.agent-workflows`; must resolve outside every managed checkout |
|
|
10
10
|
| `projects` | Nonempty array; duplicate IDs or canonical checkout roots are rejected |
|
|
11
11
|
|
|
12
12
|
| Project field | Default / meaning |
|
|
@@ -20,10 +20,64 @@ The CLI reads `agent-workflows.json`, or `--config PATH`. Unknown properties are
|
|
|
20
20
|
| `gitIdentity` | Required `name` and `email`; used by application commits |
|
|
21
21
|
| `validation` | Array of `{command,args,timeoutMs}`; no shell expansion; timeout defaults to 300000 ms |
|
|
22
22
|
| `agent` | Required default profile |
|
|
23
|
-
| `stages` | `implementation`, `
|
|
23
|
+
| `stages` | `implementation`, `publication`, `review`; each has optional `profile`, `prompt`, `promptFile`, `timeoutMs` |
|
|
24
24
|
|
|
25
25
|
Issues are selected in ascending issue-number order within each intake scan. Deduplication persists across restarts. An explicit retry is a new numbered attempt linked through `retryOf`.
|
|
26
26
|
|
|
27
|
+
## CLI environment files
|
|
28
|
+
|
|
29
|
+
Select one file explicitly for any CLI command:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
agent-workflows --env-file ./runner.env run
|
|
33
|
+
agent-workflows --env-file ./runner.env status --json
|
|
34
|
+
agent-workflows --env-file /absolute/path/runner.env monitor
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Example `runner.env` (replace placeholders locally):
|
|
38
|
+
|
|
39
|
+
```dotenv
|
|
40
|
+
AGENT_WORKFLOWS_DATABASE_URL="postgresql://USER:PASSWORD@localhost/agent_workflows"
|
|
41
|
+
GITHUB_TOKEN="YOUR_GITHUB_TOKEN"
|
|
42
|
+
APP_MODE=development # unquoted comment
|
|
43
|
+
APP_GREETING="hello # literal text"
|
|
44
|
+
APP_REFERENCE='${APP_MODE}'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- Existing process values win, including empty strings. Empty required database
|
|
48
|
+
or hosting values still fail existing validation. Missing keys are filled from
|
|
49
|
+
the file; arbitrary application variable names are supported. `databaseUrlEnv`
|
|
50
|
+
and `hosting.tokenEnv` still select which names the runner uses.
|
|
51
|
+
- Relative paths resolve from the CLI launch directory, independently of
|
|
52
|
+
`--config` and project checkouts. Absolute paths work too. No `.env` discovery
|
|
53
|
+
or multiple-file layering is performed.
|
|
54
|
+
- Parsing uses Node's literal dotenv syntax: quotes and comments are supported;
|
|
55
|
+
`$NAME`, `${NAME}`, backticks and `$(command)` in values are not expanded or
|
|
56
|
+
executed. This is not shell sourcing.
|
|
57
|
+
- The file is read once before the command action, database access, hosting
|
|
58
|
+
adapters or runner creation. Missing or unreadable files stop the command with
|
|
59
|
+
a nonzero exit and a path/error code, without printing file contents. Restart
|
|
60
|
+
the runner to pick up edits. Help only displays usage and does not load files.
|
|
61
|
+
- The merged environment is shared across all projects in the runner. Validation,
|
|
62
|
+
Git and agent worker subprocesses inherit it. Provider runtimes may apply their
|
|
63
|
+
own environment policies to tools they launch; see [providers](providers.md).
|
|
64
|
+
No per-project environment isolation is added.
|
|
65
|
+
|
|
66
|
+
Keep local environment files out of version control. Add their actual names to
|
|
67
|
+
`.gitignore` (or `.git/info/exclude`), especially inside managed checkouts where
|
|
68
|
+
untracked files interfere with cleanliness checks. Do not copy credentials into
|
|
69
|
+
configuration, prompts or issue bodies. Existing database/hosting credential
|
|
70
|
+
redaction remains in effect; arbitrary variable support does not classify every
|
|
71
|
+
application value as a secret. A GitHub API token does not configure Git push
|
|
72
|
+
credentials.
|
|
73
|
+
|
|
74
|
+
The flag belongs to `agent-workflows`, not the separate `pnpm db:migrate` command.
|
|
75
|
+
SDK callers load their own process environment before creating a runner and
|
|
76
|
+
continue passing `databaseUrl` explicitly. Node startup-only settings, such as
|
|
77
|
+
`NODE_EXTRA_CA_CERTS`, must be set before launching Node to affect the CLI process.
|
|
78
|
+
When invoking the script directly through Node, separate Node arguments from
|
|
79
|
+
application arguments: `node -- dist/src/cli.js --env-file ./runner.env status`.
|
|
80
|
+
|
|
27
81
|
## Profiles
|
|
28
82
|
|
|
29
83
|
A profile has `provider`, optional `model`, optional `reasoningEffort`, and optional `context`. Each stage merges its profile over project defaults. Switching provider discards the old provider's settings, so incompatible defaults cannot leak between providers. Each invocation starts a fresh session, including repeated custom steps.
|
|
@@ -34,8 +88,86 @@ Copilot queries its SDK model catalog for explicit settings. Supported context c
|
|
|
34
88
|
|
|
35
89
|
See [checked examples](../examples/config.ts). Model IDs in `modelOverrides` are placeholders that must be replaced with available models. No provider silently clamps or substitutes explicit options.
|
|
36
90
|
|
|
37
|
-
##
|
|
91
|
+
## Stage prompts
|
|
92
|
+
|
|
93
|
+
Omit `prompt` and `promptFile` to use the installed defaults. `init` leaves both
|
|
94
|
+
out so package upgrades update default task instructions. An override replaces
|
|
95
|
+
only task instructions; issue context, captured change evidence, permission rules
|
|
96
|
+
and output contracts remain application-owned.
|
|
97
|
+
|
|
98
|
+
### Default stage prompts
|
|
99
|
+
|
|
100
|
+
Implementation:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
Implement the supplied issue in the current checkout. Follow repository
|
|
104
|
+
instructions and existing conventions. Keep changes focused on the issue's
|
|
105
|
+
requirements, and add or update tests where needed to verify the behavior.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Publication:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
Prepare a Git commit message and a pull request or merge request title and
|
|
112
|
+
description for the supplied changes. Follow repository conventions. Describe
|
|
113
|
+
what changed and why, summarize the recorded validation accurately, and state
|
|
114
|
+
material limitations. Do not claim checks passed unless the supplied evidence
|
|
115
|
+
shows they ran and passed.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Review:
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
Independently review the supplied published changes against the issue's
|
|
122
|
+
requirements and repository conventions. Inspect the change artifacts and
|
|
123
|
+
relevant source for correctness, regressions, and missing validation. Report
|
|
124
|
+
actionable findings with supporting locations where possible. State any gaps
|
|
125
|
+
in inspection explicitly; do not present an incomplete review as a clean review.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
These exact defaults are checked against the runtime source.
|
|
129
|
+
|
|
130
|
+
Use either nonblank literal `prompt` text or a `promptFile` path, never both.
|
|
131
|
+
Files must contain nonblank UTF-8 text. Relative paths resolve from the CLI
|
|
132
|
+
configuration file's directory, independently of the launch directory; absolute
|
|
133
|
+
paths are allowed. Files load once when the runner is constructed. Restart to
|
|
134
|
+
apply edits. No templating, interpolation, or includes are supported. SDK callers
|
|
135
|
+
supply `promptBaseDirectory` for relative paths.
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
"stages": {
|
|
139
|
+
"implementation": {},
|
|
140
|
+
"publication": { "promptFile": "prompts/publication.md" },
|
|
141
|
+
"review": { "prompt": "Review correctness and missing regression tests." }
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`writing` is now `publication`; `skills` was removed. Both old keys are rejected
|
|
146
|
+
without aliases. Configure skills in the selected agent runtime and request them
|
|
147
|
+
in task text. Old invocation records and skill snapshots remain readable.
|
|
148
|
+
|
|
149
|
+
Stage timeout defaults to 30 minutes, including profile validation and at most
|
|
150
|
+
one format-correction attempt. Correction uses a fresh inspection-only session
|
|
151
|
+
and only the remaining deadline. Provider failures, cancellation, timeout and
|
|
152
|
+
workspace mutation never trigger correction. Custom text-only stages do not
|
|
153
|
+
receive format correction. Credentials belong in environment variables or
|
|
154
|
+
runtime authentication stores, not prompts.
|
|
155
|
+
|
|
156
|
+
## Change evidence
|
|
157
|
+
|
|
158
|
+
Use a `stateDirectory` outside every managed checkout. `init` chooses a sibling
|
|
159
|
+
`<checkout-name>.agent-workflows` directory. Publication and review receive a
|
|
160
|
+
small overview and an absolute index path, then read ordered artifact chunks.
|
|
161
|
+
Publication captures staged, unstaged and untracked changes. Review captures the
|
|
162
|
+
exact base and published head. Hash checks reject missing or modified evidence.
|
|
38
163
|
|
|
39
|
-
|
|
164
|
+
Text chunks are at most 64 KiB; total text evidence, including indexes, is at most
|
|
165
|
+
32 MiB per stage. Capture fails explicitly above the limit. Large indexes have
|
|
166
|
+
bounded pages; binary changes contain metadata instead of encoded content.
|
|
167
|
+
These are internal limits, not configurable model context limits.
|
|
40
168
|
|
|
41
|
-
|
|
169
|
+
Review output includes `complete` and `limitations`. Incomplete reviews preserve
|
|
170
|
+
partial findings locally and block normal review publication. Prompt content,
|
|
171
|
+
output contract and evidence identities are retained with each response attempt.
|
|
172
|
+
Changed effective prompts, including upgraded defaults, block recovery with
|
|
173
|
+
fresh-retry guidance; file edits do not change an already running instance.
|
package/docs/database.md
CHANGED
|
@@ -26,3 +26,10 @@ attempts. Runner's checkout/process safety check runs while that lock is held;
|
|
|
26
26
|
command replay skips it and does not write new events.
|
|
27
27
|
|
|
28
28
|
`src/db/locks.ts` contains the only application driver SQL: fixed, parameterized PostgreSQL session-lock calls, which have no Drizzle query-builder equivalent. Generated migration SQL and the frozen legacy-schema test fixture are intentional SQL artifacts. No interpolated SQL template strings are used for record access.
|
|
29
|
+
|
|
30
|
+
Execution history is stored in the existing run JSON record. Publication recovery
|
|
31
|
+
adds optional fields without changing SQL tables; no migration or backfill is
|
|
32
|
+
required. Legacy records remain readable, but lack the evidence needed for
|
|
33
|
+
recovery. Recovery admission atomically appends an execution, queues the same
|
|
34
|
+
run and writes an event under the project/task locks used by retry admission.
|
|
35
|
+
The persisted execution ID lets dispatch reconcile a DBOS fork across crashes.
|
package/docs/operations.md
CHANGED
|
@@ -13,12 +13,100 @@ All commands accept `--config PATH` before the subcommand.
|
|
|
13
13
|
| `logs RUN [--invocation ID]` | Local agent and validation artifacts |
|
|
14
14
|
| `pause PROJECT` / `resume PROJECT` | Queue an intake control command |
|
|
15
15
|
| `stop RUN` | Queue cancellation; success means active local work has stopped |
|
|
16
|
+
| `recover RUN` | Continue a failed publication step using completed checkpoints |
|
|
16
17
|
| `retry RUN` | Queue an explicit new attempt after checkout validation |
|
|
17
18
|
| `monitor` | Attach an interactive terminal view |
|
|
18
19
|
|
|
19
20
|
Control commands return a command ID and `pending`; inspect `status --json` or the monitor for success/failure. With no runner, commands stay pending. Run and monitor are separate processes. Closing the monitor never cancels work. Ctrl-C on the runner stops intake, cancels active work, waits for process termination and releases ownership. Queued issues remain durable for the next start.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
The monitor uses a full-screen view and restores the terminal when closed.
|
|
23
|
+
It refreshes persisted workflow state and open logs every 400 ms. Database
|
|
24
|
+
connectivity is shown separately from command acknowledgements; it does not
|
|
25
|
+
prove that a runner is alive. Requires an interactive terminal of at least
|
|
26
|
+
80 columns by 24 rows. Wide terminals show run list, summary and sessions;
|
|
27
|
+
compact terminals show the focused pane. Titles and identifiers are available
|
|
28
|
+
in full in scrollable details. `NO_COLOR=1` disables semantic colors.
|
|
29
|
+
|
|
30
|
+
| Context | Keys |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| Dashboard | Left/Right project; Tab/Shift+Tab pane; Up/Down selection or scroll |
|
|
33
|
+
| Details | Enter opens; Up/Down or PgUp/PgDn scroll; Esc returns |
|
|
34
|
+
| Progress | `[`/`]` inspect step history; End follows latest event |
|
|
35
|
+
| Sessions | `a` focuses session list; Up/Down selects invocation; `l` opens log |
|
|
36
|
+
| Validation | `v` opens validation logs |
|
|
37
|
+
| Controls | `p` pauses/resumes intake; `s` stops; `r` retries; `c` recovers publication |
|
|
38
|
+
| Monitor | `?` opens the shortcut dialog; `q` or Ctrl-C closes only the monitor |
|
|
39
|
+
| Shortcut dialog | Tab/Shift+Tab or Left/Right changes category; Up/Down scrolls; Esc closes |
|
|
40
|
+
| Logs | Up/Down or `j`/`k` scroll; PgUp/PgDn page; Left/Right pan long lines |
|
|
41
|
+
| Logs | Home/End or `g`/`G` first/last page; `f` resumes live follow |
|
|
42
|
+
| Logs | Tab selects next log; `R` toggles readable/raw presentation |
|
|
43
|
+
| Search | `/` opens; Enter applies; `n`/`N` next/previous matching record |
|
|
44
|
+
| Back | Esc dismisses search/help first, then returns from logs |
|
|
45
|
+
|
|
46
|
+
Stop, retry and publication recovery require confirmation of the selected issue;
|
|
47
|
+
The centered dialog defaults to Cancel. Tab/Shift+Tab or Left/Right switches
|
|
48
|
+
between Cancel and Confirm; Enter activates the highlighted option and Esc
|
|
49
|
+
cancels. Unavailable actions are omitted from the footer.
|
|
50
|
+
A pending command stays pending until the runner acknowledges it, including
|
|
51
|
+
while switching projects. Logs and search cannot send workflow commands.
|
|
52
|
+
|
|
53
|
+
Search is literal and covers the entire selected file, not only the visible page.
|
|
54
|
+
Lowercase queries ignore case; any uppercase character makes the query
|
|
55
|
+
case-sensitive. Search wraps at file boundaries. Scrolling or searching pauses
|
|
56
|
+
follow so arriving output does not move the view. Known agent events render as
|
|
57
|
+
readable messages/tool activity; unknown events remain visible as JSON. Raw
|
|
58
|
+
presentation preserves the stored text except unsafe terminal control codes.
|
|
59
|
+
|
|
60
|
+
Execution duration includes eligibility, preparation and waits within one
|
|
61
|
+
execution. It excludes queue waiting and gaps before publication recovery.
|
|
62
|
+
Details show each execution, its queue wait and the run's total elapsed time.
|
|
63
|
+
Completed execution durations freeze at their first terminal outcome. Records
|
|
64
|
+
without timing evidence show an em dash. Noninteractive tools use `status --json`
|
|
65
|
+
and `inspect`. See [TUI design](tui-redesign.md) for implementation boundaries.
|
|
66
|
+
|
|
67
|
+
## Observability Landscape
|
|
68
|
+
|
|
69
|
+
This section includes only options that run locally without a license key.
|
|
70
|
+
Cloud services and tools requiring a license key are excluded. These boundaries
|
|
71
|
+
apply to observability; agent and hosting providers retain their own requirements.
|
|
72
|
+
|
|
73
|
+
| Option | Available information | Integration path |
|
|
74
|
+
| ------ | --------------------- | ---------------- |
|
|
75
|
+
| Project CLI/TUI | Run outcomes, phases, invocations, sessions and local logs | Built in: `monitor`, `status --json`, `inspect RUN`, `logs RUN` |
|
|
76
|
+
| DBOS SDK CLI | Durable workflow status and step history | Connect directly to the runner's PostgreSQL database |
|
|
77
|
+
| Project `Store` API | Application records and ordered events | Build a local script or dashboard using `runs`, `run`, `invocations`, `events` and `subscribe` |
|
|
78
|
+
| `DBOSClient` | DBOS workflow and step records | Build a local inspector using `getWorkflow`, `listWorkflows` and `listWorkflowSteps`; close it with `destroy()` |
|
|
79
|
+
|
|
80
|
+
For DBOS CLI inspection from this repository:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
pnpm exec dbos workflow list --sys-db-url "$AGENT_WORKFLOWS_DATABASE_URL"
|
|
84
|
+
pnpm exec dbos workflow get "<run-id>" --sys-db-url "$AGENT_WORKFLOWS_DATABASE_URL"
|
|
85
|
+
pnpm exec dbos workflow steps "<run-id>" --sys-db-url "$AGENT_WORKFLOWS_DATABASE_URL"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use the database URL selected by `config.databaseUrlEnv` if it differs from the
|
|
89
|
+
default above. These commands use the installed SDK CLI and require no running
|
|
90
|
+
Conductor service or cloud login. See the [DBOS CLI reference](https://docs.dbos.dev/typescript/reference/cli).
|
|
91
|
+
|
|
92
|
+
The initial DBOS workflow ID equals the run ID. Publication recovery keeps the
|
|
93
|
+
run ID and adds a new DBOS execution ID; `inspect RUN` includes execution history
|
|
94
|
+
and a persisted recovery eligibility assessment. Admission performs live checks.
|
|
95
|
+
Inspect both layers: the
|
|
96
|
+
runner catches execution errors and persists application outcomes, so a DBOS
|
|
97
|
+
`SUCCESS` can accompany an application `failed` or `blocked` outcome. DBOS step
|
|
98
|
+
history does not replace the local agent/validation artifacts.
|
|
99
|
+
|
|
100
|
+
A browser dashboard is an extension path, not a bundled feature. A local server
|
|
101
|
+
could combine the [Store query/event API](api.md#query-and-event-interface) with
|
|
102
|
+
`DBOSClient.create({ systemDatabaseUrl: databaseUrl })`, joining records by run ID.
|
|
103
|
+
Neither inspector needs to launch another DBOS runtime. Keep database access on
|
|
104
|
+
the server and bind a local-only dashboard to loopback. See the
|
|
105
|
+
[inspection example](../examples/observe.ts) for Store lifecycle handling.
|
|
106
|
+
|
|
107
|
+
Route dashboard controls through `Store.request` or the runner's public controls.
|
|
108
|
+
Direct DBOS cancellation, resumption or forking bypasses application coordination
|
|
109
|
+
for process termination, checkout safety and retry admission.
|
|
22
110
|
|
|
23
111
|
## Ownership and recovery
|
|
24
112
|
|
|
@@ -30,7 +118,32 @@ Startup and phase boundaries check ownership assumptions, branch/head and actual
|
|
|
30
118
|
|
|
31
119
|
Publication effects have independent DBOS checkpoints. A task commit carries `Agent-Workflows-Run`; commit recovery checks parent and marker, push recovery checks the remote ref, request creation checks the source branch, and review publication checks stable markers. Transient publication failures use bounded retries and reconciliation. Interrupted agent stages block rather than starting another writer.
|
|
32
120
|
|
|
33
|
-
|
|
121
|
+
## Publication recovery
|
|
122
|
+
|
|
123
|
+
For the default workflow, `recover RUN` continues a run whose latest execution
|
|
124
|
+
failed at `push`, `change-request`, or `review-publication`. It reuses completed
|
|
125
|
+
checkpoints, keeps the branch, commit and publication markers, and gives the
|
|
126
|
+
failed step three new attempts. Later steps execute normally. Each execution
|
|
127
|
+
retains its outcome, error and source execution; a repeated command ID identifies
|
|
128
|
+
the same recovery.
|
|
129
|
+
|
|
130
|
+
Keep the original branch and commit checked out with a clean working tree.
|
|
131
|
+
Recovery verifies process ownership, complete checkpoint history, local artifacts,
|
|
132
|
+
remote revision, workflow version, configuration and skill contents. Environment
|
|
133
|
+
credential rotation is allowed. Changed code or execution inputs require a fresh
|
|
134
|
+
retry. Recovery honors project pause and never removes an existing project block.
|
|
135
|
+
Checks run again inside the first step that executes, including after a crash.
|
|
136
|
+
|
|
137
|
+
Use `inspect RUN` before recovery and check command outcomes afterward. Monitor
|
|
138
|
+
shows execution history and the recovery restriction, if any. Eligibility based
|
|
139
|
+
on persisted records is provisional until the runner finishes live checks.
|
|
140
|
+
|
|
141
|
+
Agent/validation failures, cancelled or blocked runs, custom workflows, and older
|
|
142
|
+
runs without recovery metadata use the existing inspection and fresh-retry path.
|
|
143
|
+
Recovery does not restore checkouts or accept arbitrary restart steps. A newer
|
|
144
|
+
fresh attempt supersedes recovery of the older run.
|
|
145
|
+
|
|
146
|
+
After a blocked/failed task that cannot be recovered:
|
|
34
147
|
|
|
35
148
|
1. Read `inspect RUN`, logs, session IDs and the local Git diff.
|
|
36
149
|
2. Establish that no worker/process group is still running. If startup reports an old PID or process journal, inspect that exact process and stop it before recovery. Never remove a live owner's lease.
|
|
@@ -41,6 +154,8 @@ A failed review after publication remains a failed automation attempt, even if i
|
|
|
41
154
|
|
|
42
155
|
## Evidence and limits
|
|
43
156
|
|
|
157
|
+
Git hooks are disabled for application-authored task commits; configure required checks as validation commands. Changed symlinks and submodules require manual handling. Checkout checks detect boundary changes but do not sandbox custom adapters or prevent unrelated local tools from writing.
|
|
158
|
+
|
|
44
159
|
Validation records say exactly which command ran, when, its exit code and artifact path. No-change work skips publication. Generated commit/request text is validated and saved before Git/API writes. Logs, prompts and errors redact configured credentials and recognized secret environment values; this does not sanitize arbitrary repository content or secrets unknown to the runner.
|
|
45
160
|
|
|
46
161
|
Back up both PostgreSQL and the state directory if history/artifacts matter. The checkout and runtime session stores are separate local state. Losing them cannot be repaired from DBOS checkpoints alone. Do not change a custom workflow's step order or rename projects while its runs are pending; use a new workflow version and finish or explicitly resolve existing runs first.
|