@mingchuno/agent-workflows 0.3.0 → 0.4.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 +25 -14
- package/dist/src/cli-config.d.ts +2 -0
- package/dist/src/cli-config.js +35 -0
- package/dist/src/cli.js +8 -23
- package/docs/api.md +10 -6
- package/docs/configuration.md +28 -18
- package/docs/database.md +2 -18
- package/docs/operations.md +17 -25
- package/docs/providers.md +2 -2
- package/package.json +1 -1
- package/docs/architecture.md +0 -41
package/README.md
CHANGED
|
@@ -52,9 +52,10 @@ agent-workflows monitor
|
|
|
52
52
|
agent-workflows status --json
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Alternatively,
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
Alternatively, set `"envFile": "./runner.env"` at the top level of
|
|
56
|
+
`agent-workflows.json` to load database, hosting and application variables from
|
|
57
|
+
one explicit file. Existing process values win, including empty strings. See
|
|
58
|
+
[environment file examples and boundaries](docs/configuration.md#cli-environment-files).
|
|
58
59
|
|
|
59
60
|
The runner fetches the configured base, creates a branch, implements an eligible issue, validates it, generates publication text, commits and pushes, creates a draft PR/MR, and publishes an independent review of its exact head. It never merges. Initial use should target a repository and issue you explicitly intend to automate; running the CLI authorizes these effects and agent usage.
|
|
60
61
|
|
|
@@ -76,6 +77,24 @@ await runner.shutdown();
|
|
|
76
77
|
|
|
77
78
|
[Custom workflow](examples/custom-workflow.ts), [complete runner](examples/run.ts), [configuration](examples/config.ts), and [inspection](examples/observe.ts) examples are type-checked with the library. The custom workflow is also exercised using controlled providers.
|
|
78
79
|
|
|
80
|
+
## Documentation
|
|
81
|
+
|
|
82
|
+
### Using the package
|
|
83
|
+
|
|
84
|
+
- [Configuration and profiles](docs/configuration.md)
|
|
85
|
+
- [Default stage prompts](docs/configuration.md#default-stage-prompts)
|
|
86
|
+
- [Public SDK API and composition](docs/api.md)
|
|
87
|
+
- [DBOS SDK direct usage](docs/api.md#dbos-sdk-direct-usage)
|
|
88
|
+
- [Authentication and provider capabilities](docs/providers.md)
|
|
89
|
+
- [CLI, TUI, observability, and recovery](docs/operations.md)
|
|
90
|
+
- [Observability landscape](docs/operations.md#observability-landscape)
|
|
91
|
+
|
|
92
|
+
### Maintaining the project
|
|
93
|
+
|
|
94
|
+
- [Architecture decisions](docs/adr/README.md)
|
|
95
|
+
- [Database maintenance](docs/database.md)
|
|
96
|
+
- [Release process](docs/releases.md)
|
|
97
|
+
|
|
79
98
|
## Development and review
|
|
80
99
|
|
|
81
100
|
[mise](https://mise.jdx.dev/getting-started.html) pins the development Node and pnpm versions. Activate it in your shell or prefix commands with `mise exec --`.
|
|
@@ -92,14 +111,6 @@ Use `pnpm start --help` to run the CLI from source. `pnpm build` emits the runti
|
|
|
92
111
|
|
|
93
112
|
`pnpm test` builds the application, then starts and removes a disposable real PostgreSQL database using `initdb`, `pg_ctl`, and `createdb` on PATH. Alternatively, set `TEST_DATABASE_URL` to a disposable database whose role can create test databases. Tests use real temporary Git repositories and controlled adapters/HTTP servers; they make no paid agent calls or writes to real hosting providers.
|
|
94
113
|
|
|
95
|
-
Schema changes and database upgrades: [database maintenance](docs/database.md).
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- [Default stage prompts](docs/configuration.md#default-stage-prompts)
|
|
99
|
-
- [Public SDK API and composition](docs/api.md)
|
|
100
|
-
- [DBOS SDK direct usage](docs/api.md#dbos-sdk-direct-usage)
|
|
101
|
-
- [Authentication and provider capabilities](docs/providers.md)
|
|
102
|
-
- [CLI, TUI, observability and recovery](docs/operations.md)
|
|
103
|
-
- [Observability Landscape](docs/operations.md#observability-landscape)
|
|
104
|
-
- [Architecture](docs/architecture.md)
|
|
105
|
-
- [Releases](docs/releases.md)
|
|
114
|
+
Schema changes and database upgrades: [database maintenance](docs/database.md).
|
|
115
|
+
Biome formats and lints supported source/configuration files; Markdown and YAML
|
|
116
|
+
are maintained manually.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { parseEnv } from "node:util";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { configSchema } from "./config.js";
|
|
5
|
+
const cliConfigurationSchema = configSchema.extend({
|
|
6
|
+
envFile: z
|
|
7
|
+
.string()
|
|
8
|
+
.refine((path) => path.trim().length > 0, "Environment file path must be nonblank")
|
|
9
|
+
.optional(),
|
|
10
|
+
});
|
|
11
|
+
export async function readCliConfiguration(path, resolveEnvironmentFile) {
|
|
12
|
+
const { envFile, ...configuration } = cliConfigurationSchema.parse(JSON.parse(await readFile(path, "utf8")));
|
|
13
|
+
if (envFile !== undefined)
|
|
14
|
+
await loadEnvironmentFile(resolveEnvironmentFile(envFile));
|
|
15
|
+
return configuration;
|
|
16
|
+
}
|
|
17
|
+
async function loadEnvironmentFile(path) {
|
|
18
|
+
let contents;
|
|
19
|
+
try {
|
|
20
|
+
contents = await readFile(path, "utf8");
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new Error(`Cannot read environment file ${path} (${error.code ?? "read failed"})`);
|
|
24
|
+
}
|
|
25
|
+
let values;
|
|
26
|
+
try {
|
|
27
|
+
values = parseEnv(contents);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`Cannot parse environment file ${path}`, { cause: error });
|
|
31
|
+
}
|
|
32
|
+
for (const [name, value] of Object.entries(values))
|
|
33
|
+
if (value !== undefined && process.env[name] === undefined)
|
|
34
|
+
process.env[name] = value;
|
|
35
|
+
}
|
package/dist/src/cli.js
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
import { realpathSync, statSync } from "node:fs";
|
|
3
3
|
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, relative, resolve } from "node:path";
|
|
5
|
-
import { parseEnv } from "node:util";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import { render } from "ink";
|
|
8
7
|
import React from "react";
|
|
9
8
|
import { createAgents } from "./adapters/agents.js";
|
|
10
9
|
import { createHosting } from "./adapters/hosting.js";
|
|
11
|
-
import {
|
|
10
|
+
import { readCliConfiguration } from "./cli-config.js";
|
|
12
11
|
import { defaultValidationTimeoutMs } from "./defaults.js";
|
|
13
12
|
import { Runner } from "./runner.js";
|
|
14
13
|
import { Store } from "./store.js";
|
|
@@ -18,27 +17,9 @@ const program = new Command()
|
|
|
18
17
|
.name("agent-workflows")
|
|
19
18
|
.description("Local durable issue-to-review workflows")
|
|
20
19
|
.option("-c, --config <file>", "configuration path", "agent-workflows.json")
|
|
21
|
-
.option("--config-base-directory <directory>", "base directory for paths contained in configuration")
|
|
22
|
-
.option("--env-file <path>", "load literal dotenv values; existing environment wins")
|
|
23
|
-
.hook("preAction", async () => {
|
|
24
|
-
const path = program.opts().envFile;
|
|
25
|
-
if (path === undefined)
|
|
26
|
-
return;
|
|
27
|
-
const file = resolve(launchDirectory, path);
|
|
28
|
-
let contents;
|
|
29
|
-
try {
|
|
30
|
-
contents = await readFile(file, "utf8");
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
throw new Error(`Cannot read environment file ${file} (${error.code ?? "read failed"})`);
|
|
34
|
-
}
|
|
35
|
-
for (const [name, value] of Object.entries(parseEnv(contents))) {
|
|
36
|
-
if (process.env[name] === undefined)
|
|
37
|
-
process.env[name] = value;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
20
|
+
.option("--config-base-directory <directory>", "base directory for paths contained in configuration");
|
|
40
21
|
async function configuration() {
|
|
41
|
-
return
|
|
22
|
+
return readCliConfiguration(configPath(), (path) => resolve(configBaseDirectory(), path));
|
|
42
23
|
}
|
|
43
24
|
function configPath() {
|
|
44
25
|
return resolve(launchDirectory, program.opts().config);
|
|
@@ -67,6 +48,9 @@ function databaseUrl(config) {
|
|
|
67
48
|
}
|
|
68
49
|
async function withStore(action) {
|
|
69
50
|
const config = await configuration();
|
|
51
|
+
await withConfiguredStore(config, action);
|
|
52
|
+
}
|
|
53
|
+
async function withConfiguredStore(config, action) {
|
|
70
54
|
const store = new Store(databaseUrl(config), config.id);
|
|
71
55
|
try {
|
|
72
56
|
await store.initialize();
|
|
@@ -210,9 +194,10 @@ program
|
|
|
210
194
|
.command("monitor")
|
|
211
195
|
.option("--notify", "notify when an observed execution reaches an outcome")
|
|
212
196
|
.action(async (options) => {
|
|
197
|
+
const config = await configuration();
|
|
213
198
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
214
199
|
throw new Error("Monitor requires an interactive terminal; use status --json instead");
|
|
215
|
-
await
|
|
200
|
+
await withConfiguredStore(config, async (store) => {
|
|
216
201
|
await render(React.createElement(Monitor, {
|
|
217
202
|
source: store,
|
|
218
203
|
notificationWriter: options.notify
|
package/docs/api.md
CHANGED
|
@@ -23,7 +23,9 @@ the next attempt; another request for the same task fails while that retry is
|
|
|
23
23
|
queued or running. Replaying the same command ID returns its existing retry,
|
|
24
24
|
without rechecking the checkout or emitting events. A command ID cannot identify
|
|
25
25
|
retries of different runs. Retry creation, project unblocking and their events
|
|
26
|
-
commit together; failure preserves the blocked state.
|
|
26
|
+
commit together; failure preserves the blocked state. The rationale for separate
|
|
27
|
+
run and execution identities is in
|
|
28
|
+
[ADR 0003](adr/0003-run-and-execution-identity.md).
|
|
27
29
|
|
|
28
30
|
## Durable operations
|
|
29
31
|
|
|
@@ -156,7 +158,8 @@ Caveats:
|
|
|
156
158
|
`Store.admitRetry` owns persisted retry admission. Runner supplies its checkout
|
|
157
159
|
and process safety check, which runs under the project lock for new admissions
|
|
158
160
|
only. This callback must not mutate Store records. Operator tools should use
|
|
159
|
-
`retry` commands or `Runner.retry`, preserving those safety checks.
|
|
161
|
+
`retry` commands or `Runner.retry`, preserving those safety checks. The locking
|
|
162
|
+
boundary is recorded in [ADR 0005](adr/0005-postgresql-persistence-boundary.md).
|
|
160
163
|
|
|
161
164
|
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.
|
|
162
165
|
|
|
@@ -182,7 +185,8 @@ markers. `Store.recoveryPlan(runId)` reports persisted eligibility and its reaso
|
|
|
182
185
|
live safety checks happen at admission and execution. Runs without execution
|
|
183
186
|
metadata remain readable and retryable, but cannot be recovered.
|
|
184
187
|
|
|
185
|
-
Recovery
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
Recovery preserves the original workflow input and completed checkpoint prefix.
|
|
189
|
+
The accepted command ID identifies the new execution so uncertain dispatch can
|
|
190
|
+
be reconciled after a crash. Live checks still run in the first non-replayed
|
|
191
|
+
operation. See [ADR 0003](adr/0003-run-and-execution-identity.md) for the complete
|
|
192
|
+
identity and recovery decision.
|
package/docs/configuration.md
CHANGED
|
@@ -15,6 +15,9 @@ and is canonicalized before startup.
|
|
|
15
15
|
| `stateDirectory` | `.agent-workflows`; relative to the configuration base and outside every managed checkout |
|
|
16
16
|
| `projects` | Nonempty array; duplicate IDs or canonical checkout roots are rejected |
|
|
17
17
|
|
|
18
|
+
The JSON file also accepts optional CLI-only `envFile`; it is intentionally not
|
|
19
|
+
part of the public SDK `Configuration` type.
|
|
20
|
+
|
|
18
21
|
| Project field | Default / meaning |
|
|
19
22
|
| ---------------------- | --------------------------------------------------------------------------------------------------- |
|
|
20
23
|
| `id`, `checkout` | Required stable identity and existing Git repository root; relative to the configuration base |
|
|
@@ -43,14 +46,17 @@ is the relative sibling `<checkout-name>.agent-workflows`.
|
|
|
43
46
|
|
|
44
47
|
## CLI environment files
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
Set the optional top-level `envFile` property to load one file for every CLI
|
|
50
|
+
command that reads the configuration:
|
|
47
51
|
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
agent-workflows --env-file ./runner.env status --json
|
|
51
|
-
agent-workflows --env-file /absolute/path/runner.env monitor
|
|
52
|
+
```json
|
|
53
|
+
"envFile": "./runner.env"
|
|
52
54
|
```
|
|
53
55
|
|
|
56
|
+
Add this alongside the other top-level properties in `agent-workflows.json`.
|
|
57
|
+
`envFile` is a CLI-file setting, not part of the public SDK `Configuration`.
|
|
58
|
+
SDK callers continue to prepare their own process environment.
|
|
59
|
+
|
|
54
60
|
Example `runner.env` (replace placeholders locally):
|
|
55
61
|
|
|
56
62
|
```dotenv
|
|
@@ -65,16 +71,19 @@ APP_REFERENCE='${APP_MODE}'
|
|
|
65
71
|
or hosting values still fail existing validation. Missing keys are filled from
|
|
66
72
|
the file; arbitrary application variable names are supported. `databaseUrlEnv`
|
|
67
73
|
and `hosting.tokenEnv` still select which names the runner uses.
|
|
68
|
-
- Relative paths resolve from the
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
- Relative paths resolve from the effective configuration base: the directory
|
|
75
|
+
containing the resolved configuration file, or `--config-base-directory`
|
|
76
|
+
when supplied. Absolute paths work too. Omitting `envFile` performs no `.env`
|
|
77
|
+
discovery. Multiple-file layering is not supported.
|
|
71
78
|
- Parsing uses Node's literal dotenv syntax: quotes and comments are supported;
|
|
72
79
|
`$NAME`, `${NAME}`, backticks and `$(command)` in values are not expanded or
|
|
73
80
|
executed. This is not shell sourcing.
|
|
74
|
-
- The
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
- The configuration is validated before its environment file can be discovered.
|
|
82
|
+
The file is then read once before database access, hosting adapters or runner
|
|
83
|
+
creation. Missing, unreadable or invalid files stop the command with a nonzero
|
|
84
|
+
exit without printing file contents. Restart the runner to pick up edits.
|
|
85
|
+
`init` creates a configuration without `envFile`; help and `init` do not load
|
|
86
|
+
an environment file.
|
|
78
87
|
- The merged environment is shared across all projects in the runner. Validation,
|
|
79
88
|
Git and agent worker subprocesses inherit it. Provider runtimes may apply their
|
|
80
89
|
own environment policies to tools they launch; see [providers](providers.md).
|
|
@@ -88,12 +97,13 @@ redaction remains in effect; arbitrary variable support does not classify every
|
|
|
88
97
|
application value as a secret. A GitHub API token does not configure Git push
|
|
89
98
|
credentials.
|
|
90
99
|
|
|
91
|
-
The
|
|
92
|
-
SDK callers load their own process environment before
|
|
93
|
-
continue passing `databaseUrl` explicitly.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
The setting belongs to the CLI configuration file, not the separate
|
|
101
|
+
`pnpm db:migrate` command. SDK callers load their own process environment before
|
|
102
|
+
creating a runner and continue passing `databaseUrl` explicitly. The setting's
|
|
103
|
+
path and contents are not part of publication-recovery fingerprints, so
|
|
104
|
+
credential rotation does not invalidate recovery. Node startup-only settings,
|
|
105
|
+
such as `NODE_EXTRA_CA_CERTS`, must be set before launching Node to affect the
|
|
106
|
+
CLI process.
|
|
97
107
|
|
|
98
108
|
## Profiles
|
|
99
109
|
|
package/docs/database.md
CHANGED
|
@@ -15,21 +15,5 @@ Do not edit applied migration files or use schema push against existing data. Ad
|
|
|
15
15
|
|
|
16
16
|
The initial migration adopts the original application's identical tables using `IF NOT EXISTS`, preserving records and constraints. This supports the original schema, not arbitrary manually altered schemas; inspect and reconcile any local schema changes first.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`Store` uses typed Drizzle inserts, updates and selects. Concurrent JSON record patches use a transaction and row lock to preserve unrelated fields. Full-scope run and invocation queries sort their JSON fields in memory; introduce typed indexed columns if history size requires database pagination.
|
|
21
|
-
|
|
22
|
-
Retry admission locks the project row before checking task history, then commits
|
|
23
|
-
the new run, project unblocking and admission events in one transaction. The
|
|
24
|
-
project lock serializes requests even when they target different historical
|
|
25
|
-
attempts. Runner's checkout/process safety check runs while that lock is held;
|
|
26
|
-
command replay skips it and does not write new events.
|
|
27
|
-
|
|
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.
|
|
18
|
+
The persistence and locking rationale is recorded in
|
|
19
|
+
[ADR 0005](adr/0005-postgresql-persistence-boundary.md).
|
package/docs/operations.md
CHANGED
|
@@ -93,7 +93,7 @@ or `unavailable`. Noninteractive tools use `status --json` and `inspect`. Run
|
|
|
93
93
|
details keeps complete errors under Diagnostics and exact identifiers, paths,
|
|
94
94
|
profiles and ISO timestamps under Technical details.
|
|
95
95
|
|
|
96
|
-
## Observability
|
|
96
|
+
## Observability landscape
|
|
97
97
|
|
|
98
98
|
This section includes only options that run locally without a license key.
|
|
99
99
|
Cloud services and tools requiring a license key are excluded. These boundaries
|
|
@@ -121,38 +121,30 @@ Conductor service or cloud login. See the [DBOS CLI reference](https://docs.dbos
|
|
|
121
121
|
The initial DBOS workflow ID equals the run ID. Publication recovery keeps the
|
|
122
122
|
run ID and adds a new DBOS execution ID; `inspect RUN` includes execution history
|
|
123
123
|
and a persisted recovery eligibility assessment. Admission performs live checks.
|
|
124
|
-
Inspect both layers: the
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
A browser dashboard is an extension path, not a bundled feature. A local server
|
|
130
|
-
could combine the [Store query/event API](api.md#query-and-event-interface) with
|
|
131
|
-
`DBOSClient.create({ systemDatabaseUrl: databaseUrl })`, joining records by run ID.
|
|
132
|
-
Neither inspector needs to launch another DBOS runtime. Keep database access on
|
|
133
|
-
the server and bind a local-only dashboard to loopback. See the
|
|
134
|
-
[inspection example](../examples/observe.ts) for Store lifecycle handling.
|
|
135
|
-
|
|
136
|
-
Route dashboard controls through `Store.request` or the runner's public controls.
|
|
137
|
-
Direct DBOS cancellation, resumption or forking bypasses application coordination
|
|
138
|
-
for process termination, checkout safety and retry admission.
|
|
124
|
+
Inspect both layers: the runner catches execution errors and persists application
|
|
125
|
+
outcomes, so DBOS `SUCCESS` can accompany an application `failed` or `blocked`
|
|
126
|
+
outcome. DBOS step history does not replace local agent or validation artifacts.
|
|
127
|
+
See [ADR 0003](adr/0003-run-and-execution-identity.md) for the identity model.
|
|
139
128
|
|
|
140
129
|
## Ownership and recovery
|
|
141
130
|
|
|
142
|
-
Only the runner may edit or switch managed checkouts while it is active.
|
|
131
|
+
Only the runner may edit or switch managed checkouts while it is active.
|
|
132
|
+
PostgreSQL advisory locks, a local Git-directory lease, and worker/validation
|
|
133
|
+
process journals prevent concurrent ownership and reuse while old work may still
|
|
134
|
+
run. See [ADR 0002](adr/0002-existing-checkouts-and-exclusive-ownership.md) for
|
|
135
|
+
the checkout and concurrency tradeoff.
|
|
143
136
|
|
|
144
137
|
Git process journals live in `<git-directory>/agent-workflows-processes/`, independently of the configured state directory. A surviving Git process blocks ownership acquisition after a crash. Stop requests propagate to active fetch, staging, commit and push commands; interrupted effects still require reconciliation.
|
|
145
138
|
|
|
146
139
|
Startup and phase boundaries check ownership assumptions, branch/head and actual changes. Unfinished files are never reset, cleaned, stashed or discarded automatically. Dirty files, unresolved Git operations, branch collisions, unexpected mutations and ambiguous agent recovery become inspectable blocked states. Other eligible projects continue.
|
|
147
140
|
|
|
148
|
-
Publication effects have independent DBOS checkpoints. A task commit
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
stages block rather than starting another writer.
|
|
141
|
+
Publication effects have independent DBOS checkpoints. A task commit carries
|
|
142
|
+
exactly one `Agent-Workflows-Run` marker and, by default, co-author trailers for
|
|
143
|
+
providers with retained writable contributions. Commit, push, request creation,
|
|
144
|
+
and review publication reconcile their durable identities before retrying an
|
|
145
|
+
ambiguous effect. Interrupted agent stages block rather than starting another
|
|
146
|
+
writer. See [ADR 0003](adr/0003-run-and-execution-identity.md) for the recovery
|
|
147
|
+
boundary.
|
|
156
148
|
|
|
157
149
|
## Publication recovery
|
|
158
150
|
|
package/docs/providers.md
CHANGED
|
@@ -21,7 +21,7 @@ The runner deliberately does not automatically resume interrupted agent work. Ru
|
|
|
21
21
|
|
|
22
22
|
## Environment inheritance
|
|
23
23
|
|
|
24
|
-
CLI
|
|
24
|
+
CLI `envFile` values reach validation commands, Git subprocesses and agent
|
|
25
25
|
workers through the runner's process environment. SDK callers get the same
|
|
26
26
|
inheritance from their own process environment. The installed Codex SDK forwards
|
|
27
27
|
that environment to its executable; Copilot uses it for its local runtime, with
|
|
@@ -58,7 +58,7 @@ In GitHub **Settings → Developer settings → Personal access tokens → Fine-
|
|
|
58
58
|
|
|
59
59
|
Git push uses the checkout's configured remote and Git credentials independently of this API token. The API adapter does not require **Contents** permission. If you also use this PAT for HTTPS Git pushes, grant **Contents: Read and write**; pushing changes to `.github/workflows/` additionally requires **Workflows: Read and write**. Do not embed credentials in remote URLs.
|
|
60
60
|
|
|
61
|
-
If access is denied, check the selected owner/repository, PR write permission, token expiration, organization approval, and the token owner's repository access. If you replace the token value, restart the runner with the updated environment; existing environment variables override
|
|
61
|
+
If access is denied, check the selected owner/repository, PR write permission, token expiration, organization approval, and the token owner's repository access. If you replace the token value, restart the runner with the updated environment; existing environment variables override configured `envFile` values. An already failed run requires explicit [recovery](operations.md#ownership-and-recovery); updating permissions does not restart it.
|
|
62
62
|
|
|
63
63
|
References: GitHub's [PAT creation guide](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens), [issue permissions](https://docs.github.com/en/rest/issues/issues#list-repository-issues), [PR creation permissions](https://docs.github.com/en/rest/pulls/pulls#create-a-pull-request), and [review permissions](https://docs.github.com/en/rest/pulls/reviews#create-a-review-for-a-pull-request).
|
|
64
64
|
|
package/package.json
CHANGED
package/docs/architecture.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
DBOS owns workflow execution, durable steps and concurrency-one project queues. The runner only discovers candidates, dispatches durable identities and handles local operator commands. It does not introduce a workflow language or an interchangeable scheduler.
|
|
4
|
-
|
|
5
|
-
- `config.ts` / `domain.ts`: validated configuration, vocabulary and adapter contracts.
|
|
6
|
-
- `runner.ts`: local ownership, intake/deduplication, DBOS lifecycle and operator controls.
|
|
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.
|
|
11
|
-
- `workspace.ts`: existing-checkout Git operations and change verification.
|
|
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.
|
|
13
|
-
- `adapters/`: provider clients and isolated SDK workers.
|
|
14
|
-
- `runtime/`: process groups, ownership journals and redacted logging.
|
|
15
|
-
- `cli.ts` / `tui/`: shared command/query interfaces.
|
|
16
|
-
|
|
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.
|
|
18
|
-
|
|
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.
|
|
20
|
-
|
|
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.
|
|
22
|
-
|
|
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.
|
|
24
|
-
|
|
25
|
-
## Package boundary
|
|
26
|
-
|
|
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.
|