akm-cli 0.9.10 → 0.9.12
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/CHANGELOG.md +226 -0
- package/STABILITY.md +28 -15
- package/dist/assets/hints/cli-hints-full.md +1 -1
- package/dist/assets/improve-strategies/consolidate.json +1 -1
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/thorough.json +1 -2
- package/dist/cli/shared.js +16 -4
- package/dist/cli.js +15 -13
- package/dist/commands/agent/agent-dispatch.js +8 -0
- package/dist/commands/command/execution-source-loader.js +25 -22
- package/dist/commands/command/portable-template.js +4 -26
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env-binding.js +10 -3
- package/dist/commands/env/env-cli.js +7 -0
- package/dist/commands/env/secret-cli.js +15 -4
- package/dist/commands/health/checks.js +209 -78
- package/dist/commands/health/improve-metrics.js +12 -0
- package/dist/commands/health.js +16 -4
- package/dist/commands/improve/distill/quality-gate.js +15 -7
- package/dist/commands/improve/distill.js +28 -12
- package/dist/commands/improve/eval-cases.js +9 -2
- package/dist/commands/improve/execution.js +1 -2
- package/dist/commands/improve/extract.js +82 -56
- package/dist/commands/improve/improve-strategies.js +26 -8
- package/dist/commands/improve/improve.js +32 -4
- package/dist/commands/improve/loop-stages.js +13 -3
- package/dist/commands/improve/preparation.js +9 -6
- package/dist/commands/improve/reflect.js +61 -77
- package/dist/commands/lint/index.js +3 -1
- package/dist/commands/migrate-cli.js +6 -4
- package/dist/commands/proposal/drain-policies.js +22 -2
- package/dist/commands/proposal/repository.js +4 -4
- package/dist/commands/proposal/validators/proposal-quality-validators.js +23 -2
- package/dist/commands/proposal/validators/proposals.js +10 -19
- package/dist/commands/read/show.js +42 -31
- package/dist/commands/registry-cli.js +4 -2
- package/dist/commands/sources/init.js +4 -8
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-clone.js +5 -7
- package/dist/commands/sources/sources-cli.js +3 -5
- package/dist/commands/tasks/tasks-cli.js +36 -12
- package/dist/commands/tasks/tasks.js +38 -35
- package/dist/commands/tasks/validate.js +186 -0
- package/dist/commands/url-checker.js +75 -16
- package/dist/commands/workflow-cli.js +17 -15
- package/dist/core/activation-policy.js +31 -3
- package/dist/core/adapter/execution-source.js +39 -11
- package/dist/core/asset/stash-meta.js +7 -41
- package/dist/core/bundle-id.js +7 -1
- package/dist/core/common.js +8 -17
- package/dist/core/config/config-schema.js +3 -23
- package/dist/core/config/config-walker.js +50 -4
- package/dist/core/config/config.js +21 -5
- package/dist/core/config/legacy-source-shape-shim.js +79 -0
- package/dist/core/config/schema/embedding.js +2 -2
- package/dist/core/config/schema/engines.js +19 -2
- package/dist/core/config/schema/index-config.js +19 -21
- package/dist/core/config/schema/primitives.js +21 -10
- package/dist/core/config/schema/sources-bundles.js +1 -6
- package/dist/core/errors.js +2 -3
- package/dist/core/improve-result.js +8 -0
- package/dist/core/improve-types.js +17 -0
- package/dist/core/json-schema.js +1 -11
- package/dist/core/maintenance-barrier.js +17 -2
- package/dist/core/paths.js +124 -15
- package/dist/core/state/migrations.js +28 -0
- package/dist/core/state-db.js +28 -1
- package/dist/core/write-source.js +6 -6
- package/dist/indexer/bundle-identity-guard.js +3 -0
- package/dist/indexer/ensure-index.js +5 -0
- package/dist/indexer/indexer.js +11 -3
- package/dist/indexer/lookup/adapter-concept-owner.js +14 -3
- package/dist/indexer/passes/metadata.js +16 -5
- package/dist/indexer/search/search-fields.js +1 -30
- package/dist/indexer/search/search-source.js +3 -2
- package/dist/integrations/agent/engine-resolution.js +107 -4
- package/dist/integrations/agent/execution-lowering.js +15 -2
- package/dist/integrations/agent/model-map.js +16 -10
- package/dist/integrations/agent/prompts.js +13 -6
- package/dist/integrations/agent/runner-dispatch.js +16 -3
- package/dist/integrations/agent/runner.js +2 -0
- package/dist/integrations/lockfile.js +22 -7
- package/dist/llm/client.js +16 -0
- package/dist/llm/index-passes.js +3 -2
- package/dist/output/shapes/passthrough.js +10 -3
- package/dist/output/shapes.js +5 -3
- package/dist/output/text/workflow-format.js +8 -1
- package/dist/scripts/akm-migrate-node.js +2028 -1613
- package/dist/scripts/akm-migrate.js +2027 -1612
- package/dist/setup/setup.js +14 -21
- package/dist/sources/include.js +150 -20
- package/dist/sources/providers/git-install.js +14 -12
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/snapshot-fetchers/website-ingest.js +54 -16
- package/dist/sources/website-url.js +12 -4
- package/dist/storage/engines/sqlite-migrations.js +40 -10
- package/dist/storage/like-pattern.js +7 -0
- package/dist/storage/repositories/extract-sessions-repository.js +23 -0
- package/dist/storage/repositories/index-connection.js +27 -10
- package/dist/storage/repositories/index-entry-schema.js +19 -2
- package/dist/storage/repositories/index-schema.js +30 -9
- package/dist/storage/repositories/proposals-repository.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +14 -7
- package/dist/storage/repositories/workflow-runs-repository.js +15 -1
- package/dist/storage/sqlite-read-snapshot.js +11 -9
- package/dist/tasks/backends/cron.js +34 -5
- package/dist/tasks/backends/launchd.js +23 -26
- package/dist/tasks/backends/schtasks.js +50 -3
- package/dist/tasks/frozen-script.js +2 -0
- package/dist/tasks/prepare/prepare.js +2 -7
- package/dist/tasks/prepare/script-capture.js +38 -6
- package/dist/tasks/schedule.js +154 -13
- package/dist/tasks/scheduler-sync.js +51 -25
- package/dist/tasks/source/task-source-v3-frozen.js +0 -1
- package/dist/tasks/source/task-source-v4.js +0 -1
- package/dist/workflows/exec/child-workflow.js +2 -3
- package/dist/workflows/exec/dispatch-redaction.js +21 -7
- package/dist/workflows/exec/exec-unit.js +3 -4
- package/dist/workflows/exec/run-workflow.js +19 -10
- package/dist/workflows/exec/step-work.js +35 -56
- package/dist/workflows/freeze/resolve-steps.js +19 -11
- package/dist/workflows/freeze/source-freeze.js +7 -0
- package/dist/workflows/freeze/targets/child-workflow.js +12 -18
- package/dist/workflows/freeze/targets/command.js +14 -2
- package/dist/workflows/ir/environment-v4.js +4 -2
- package/dist/workflows/ir/freeze-v4.js +2 -5
- package/dist/workflows/ir/plan-hash.js +0 -3
- package/dist/workflows/ir/schema-v4.js +14 -9
- package/dist/workflows/ir/schema.js +1 -3
- package/dist/workflows/resource-limits.js +35 -48
- package/dist/workflows/runtime/plan-classifier.js +89 -41
- package/dist/workflows/runtime/run-outputs.js +1 -21
- package/dist/workflows/runtime/runs.js +76 -150
- package/dist/workflows/source-files.js +28 -54
- package/dist/workflows/source-ir/program.js +2 -2
- package/dist/workflows/source-ir/semantics.js +5 -23
- package/docs/integration/bundling-akm.md +1 -1
- package/docs/migration/v0.8-to-v0.9.md +32 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +20 -0
- package/docs/reference/cli.md +105 -22
- package/docs/reference/configuration.md +12 -2
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/tasks.md +8 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +11 -8
|
@@ -15,6 +15,7 @@ import path from "node:path";
|
|
|
15
15
|
import { compareCodePoints, toPosix } from "../core/common.js";
|
|
16
16
|
import { UsageError } from "../core/errors.js";
|
|
17
17
|
import { canonicalizeWorkflowName, WORKFLOW_EXTENSIONS } from "../core/recognition-util.js";
|
|
18
|
+
import { warnOnce } from "../core/warn.js";
|
|
18
19
|
export class WorkflowSourceRejectionError extends UsageError {
|
|
19
20
|
sourcePaths;
|
|
20
21
|
constructor(message, code, sourcePaths) {
|
|
@@ -34,23 +35,6 @@ export class WorkflowSourceCollisionError extends WorkflowSourceRejectionError {
|
|
|
34
35
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
export class WorkflowSourceDomainError extends WorkflowSourceRejectionError {
|
|
38
|
-
canonicalName;
|
|
39
|
-
constructor(canonicalName, sourcePaths, issues, collidingSourcePaths) {
|
|
40
|
-
const sortedPaths = [...sourcePaths].sort(compareCodePoints);
|
|
41
|
-
const sortedCollisions = [...collidingSourcePaths].sort(compareCodePoints);
|
|
42
|
-
const code = issues.some((issue) => issue.code === "PATH_ESCAPE_VIOLATION")
|
|
43
|
-
? "PATH_ESCAPE_VIOLATION"
|
|
44
|
-
: "WORKFLOW_SOURCE_INVALID";
|
|
45
|
-
const collisionDetail = sortedCollisions.length > 1 ? ` Valid owners also collide: ${sortedCollisions.join(", ")}.` : "";
|
|
46
|
-
super(`Workflow "${canonicalName}" has an invalid source ownership domain across candidates: ${sortedPaths.join(", ")}. ` +
|
|
47
|
-
`Problems: ${issues.map((issue) => issue.message).join(" ")}${collisionDetail} ` +
|
|
48
|
-
"Every candidate in the canonical domain is rejected until all invalid or duplicate sources are removed.", code, sortedPaths);
|
|
49
|
-
this.name = "WorkflowSourceDomainError";
|
|
50
|
-
this.canonicalName = canonicalName;
|
|
51
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
38
|
export class WorkflowSourceIdentityError extends UsageError {
|
|
55
39
|
constructor(ref, indexedPath, authoritativePath) {
|
|
56
40
|
super(`Indexed workflow source identity for "${ref}" points to ${indexedPath}, but the authoritative source is ${authoritativePath}. ` +
|
|
@@ -171,11 +155,7 @@ export function listWorkflowSourceFiles(sourceRoot, adapterId, name) {
|
|
|
171
155
|
});
|
|
172
156
|
}
|
|
173
157
|
candidates.sort((left, right) => compareCodePoints(left.relativePath, right.relativePath));
|
|
174
|
-
|
|
175
|
-
if (issues.length > 0) {
|
|
176
|
-
throw workflowSourceDomainError(adapterId, canonicalName, candidates, sources, issues);
|
|
177
|
-
}
|
|
178
|
-
return sources;
|
|
158
|
+
return inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
|
|
179
159
|
}
|
|
180
160
|
/**
|
|
181
161
|
* Resolve a pre-enumerated set of authored workflow candidates in one batch.
|
|
@@ -233,47 +213,44 @@ export function resolveWorkflowSourceDomains(sourceRoot, adapterId, sourcePaths)
|
|
|
233
213
|
for (const canonicalName of [...candidatesByName.keys()].sort(compareCodePoints)) {
|
|
234
214
|
const candidates = candidatesByName.get(canonicalName) ?? [];
|
|
235
215
|
candidates.sort((left, right) => compareCodePoints(left.relativePath, right.relativePath));
|
|
236
|
-
const
|
|
216
|
+
const sources = inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
|
|
237
217
|
const sourcePaths = candidates.map((candidate) => candidate.relativePath);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
});
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (sources.length > 1) {
|
|
247
|
-
resolutions.push({
|
|
248
|
-
canonicalName,
|
|
249
|
-
sourcePaths,
|
|
250
|
-
rejection: new WorkflowSourceCollisionError(adapterId === "akm" ? `workflows/${canonicalName}` : canonicalName, sources.map((source) => source.relativePath)),
|
|
251
|
-
});
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
resolutions.push({ canonicalName, sourcePaths, source: sources[0] });
|
|
218
|
+
resolutions.push({
|
|
219
|
+
canonicalName,
|
|
220
|
+
sourcePaths,
|
|
221
|
+
source: pickWorkflowSource(adapterId, canonicalName, sources),
|
|
222
|
+
});
|
|
255
223
|
}
|
|
256
224
|
return resolutions;
|
|
257
225
|
}
|
|
258
226
|
function inspectWorkflowSourceDomain(candidates, canonicalName, realRoot) {
|
|
259
227
|
const sources = [];
|
|
260
|
-
const issues = [];
|
|
261
228
|
for (const candidate of candidates) {
|
|
262
229
|
const inspection = inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot);
|
|
263
|
-
if (inspection.source)
|
|
230
|
+
if (inspection.source) {
|
|
264
231
|
sources.push(inspection.source);
|
|
265
|
-
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
for (const issue of inspection.issues) {
|
|
235
|
+
warnOnce(`workflow-source-invalid:${issue.sourcePaths.join(",")}`, issue.message);
|
|
236
|
+
}
|
|
266
237
|
}
|
|
267
|
-
return
|
|
238
|
+
return sources;
|
|
268
239
|
}
|
|
269
|
-
function
|
|
270
|
-
|
|
240
|
+
function pickWorkflowSource(adapterId, canonicalName, sources) {
|
|
241
|
+
if (sources.length <= 1)
|
|
242
|
+
return sources[0];
|
|
243
|
+
const winner = [...sources].sort((left, right) => left.format === right.format ? 0 : left.format === "markdown" ? -1 : 1)[0];
|
|
244
|
+
const shadowed = sources.filter((source) => source !== winner);
|
|
245
|
+
const displayName = adapterId === "akm" ? `workflows/${canonicalName}` : canonicalName;
|
|
246
|
+
warnOnce(`workflow-source-collision:${displayName}`, `Workflow "${displayName}" has both a .md and .yml source (${shadowed
|
|
247
|
+
.map((source) => source.relativePath)
|
|
248
|
+
.join(", ")} shadowed by ${winner?.relativePath}); using the .md source. Remove the shadowed sibling to ` +
|
|
249
|
+
"silence this warning.");
|
|
250
|
+
return winner;
|
|
271
251
|
}
|
|
272
252
|
function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
|
|
273
253
|
const issues = [];
|
|
274
|
-
const nestedSuffix = WORKFLOW_EXTENSIONS.find((suffix) => candidate.extensionlessStem.toLowerCase().endsWith(suffix));
|
|
275
|
-
if (nestedSuffix)
|
|
276
|
-
issues.push(new WorkflowSourceNameError(candidate.relativePath, nestedSuffix));
|
|
277
254
|
let authoredStat;
|
|
278
255
|
try {
|
|
279
256
|
authoredStat = fs.lstatSync(candidate.path);
|
|
@@ -327,11 +304,8 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
|
|
|
327
304
|
/** Return the sole owner, throw on a collision, or return undefined when absent. */
|
|
328
305
|
export function resolveUniqueWorkflowSource(sourceRoot, adapterId, name) {
|
|
329
306
|
const sources = listWorkflowSourceFiles(sourceRoot, adapterId, name);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
throw new WorkflowSourceCollisionError(adapterId === "akm" ? `workflows/${canonicalName}` : canonicalName, sources.map((source) => source.relativePath));
|
|
333
|
-
}
|
|
334
|
-
return sources[0];
|
|
307
|
+
const canonicalName = sources[0]?.canonicalName ?? canonicalizeWorkflowName(normalizeName(name));
|
|
308
|
+
return pickWorkflowSource(adapterId, canonicalName, sources);
|
|
335
309
|
}
|
|
336
310
|
/** Compare an indexed path with the single authoritative on-disk source. */
|
|
337
311
|
export function assertIndexedWorkflowSourceIdentity(ref, indexedPath, authoritative) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { parseBuiltinCommandAction } from "../../commands/command/builtin-action.js";
|
|
5
|
-
import {
|
|
5
|
+
import { PORTABLE_ARGUMENTS_PLACEHOLDER } from "../../commands/command/portable-template.js";
|
|
6
6
|
/** Lower one adapter-neutral source-IR step into the shared execution unit. */
|
|
7
7
|
export function sourceStepProgramUnit(source) {
|
|
8
8
|
const unit = {
|
|
@@ -32,7 +32,7 @@ export function sourceStepInstructions(source) {
|
|
|
32
32
|
}
|
|
33
33
|
if (source.commandMode === "literal")
|
|
34
34
|
return action.content;
|
|
35
|
-
return
|
|
35
|
+
return action.content.split(PORTABLE_ARGUMENTS_PLACEHOLDER).join(action.arguments ?? "");
|
|
36
36
|
}
|
|
37
37
|
if (source.uses !== undefined)
|
|
38
38
|
return `Invoke local target ${source.uses}.`;
|
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { parseBuiltinCommandAction } from "../../commands/command/builtin-action.js";
|
|
8
|
-
import { validatePortableCommandTemplate } from "../../commands/command/portable-template.js";
|
|
9
8
|
import { parseSchedule } from "../../tasks/schedule.js";
|
|
10
9
|
import { classifyWorkflowSourceUses } from "./uses.js";
|
|
11
|
-
const TOKEN_SAFE_RUN = /^[A-Za-z0-9_./:@+=,-]+(?: [A-Za-z0-9_./:@+=,-]+)*$/;
|
|
12
10
|
export class WorkflowSourceSemanticError extends Error {
|
|
13
11
|
code;
|
|
14
12
|
constructor(code, message) {
|
|
@@ -34,17 +32,10 @@ export function canonicalizeWorkflowRun(value) {
|
|
|
34
32
|
if (value.includes("${{")) {
|
|
35
33
|
throw new WorkflowSourceSemanticError("unsupported-github-expression", "GitHub expressions and contexts are not supported.");
|
|
36
34
|
}
|
|
37
|
-
if (value.includes("\
|
|
38
|
-
throw new WorkflowSourceSemanticError("
|
|
35
|
+
if (value.includes("\0")) {
|
|
36
|
+
throw new WorkflowSourceSemanticError("invalid-exec-argv", "Local run may not contain NUL bytes.");
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
.trim()
|
|
42
|
-
.split(/[ \t]+/)
|
|
43
|
-
.join(" ");
|
|
44
|
-
if (!TOKEN_SAFE_RUN.test(canonical)) {
|
|
45
|
-
throw new WorkflowSourceSemanticError("unsafe-run-syntax", "Local run accepts only whitespace-separated safe tokens; shell expansion and operators are unsupported.");
|
|
46
|
-
}
|
|
47
|
-
return canonical;
|
|
38
|
+
return value;
|
|
48
39
|
}
|
|
49
40
|
export function canonicalizeWorkflowWorkingDirectory(value, workspaceRoot) {
|
|
50
41
|
if (hasControlCharacter(value)) {
|
|
@@ -125,17 +116,8 @@ export function validateWorkflowBuiltinCommand(value, mode) {
|
|
|
125
116
|
if (effectiveMode === "stored-ref") {
|
|
126
117
|
throw new WorkflowSourceSemanticError("builtin-command-inputs", "Inline akm/command content cannot use commandMode stored-ref.");
|
|
127
118
|
}
|
|
128
|
-
if (effectiveMode === "literal") {
|
|
129
|
-
|
|
130
|
-
throw new WorkflowSourceSemanticError("builtin-command-inputs", "Literal akm/command content cannot declare arguments because no substitution occurs.");
|
|
131
|
-
}
|
|
132
|
-
return action;
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
validatePortableCommandTemplate(action.content, "inline workflow command");
|
|
136
|
-
}
|
|
137
|
-
catch (cause) {
|
|
138
|
-
throw new WorkflowSourceSemanticError("builtin-command-inputs", cause instanceof Error ? cause.message : "Invalid portable command template.");
|
|
119
|
+
if (effectiveMode === "literal" && action.arguments !== undefined) {
|
|
120
|
+
throw new WorkflowSourceSemanticError("builtin-command-inputs", "Literal akm/command content cannot declare arguments because no substitution occurs.");
|
|
139
121
|
}
|
|
140
122
|
return action;
|
|
141
123
|
}
|
|
@@ -259,7 +259,7 @@ rather than rely on `$HOME`-derived defaults (names verified against
|
|
|
259
259
|
| `AKM_CONFIG_DIR` | `config.json`'s directory. |
|
|
260
260
|
| `AKM_DATA_DIR` | Durable, non-regenerable data: **`index.db` and `state.db` live here.** This is the directory a migration snapshot's safety copy sits beside. |
|
|
261
261
|
| `AKM_CACHE_DIR` | Regenerable cache: registry downloads, config backups, task logs. Safe to discard between image builds (not between boots of the same running install). |
|
|
262
|
-
| `AKM_STATE_DIR` | **Not** where `state.db` lives, despite the name — this is the XDG "state" directory
|
|
262
|
+
| `AKM_STATE_DIR` | **Not** where `state.db` lives, despite the name — this is the XDG "state" directory. Holds scheduled-task invocation context, companion-plugin hook state (Claude Code / OpenCode hook logs), and, per stash, `akm improve`'s machine-local writers (`improve/distill-rejected/`, `improve/eval-cases/`, `improve/measurement/verdicts/`) and whole-run lock (`locks/`) — see [Storage locations](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/storage-locations.md). Set it anyway if you schedule akm tasks inside the image, so that context is captured consistently rather than falling back to `$HOME/.local/state/akm`. |
|
|
263
263
|
|
|
264
264
|
Set all five to paths that persist across container restarts (a mounted
|
|
265
265
|
volume), or `akm migrate apply` will see an empty `state.db` on every boot
|
|
@@ -112,6 +112,38 @@ IR and freeze the durable plan v4 family's executable `irVersion: 5` format.
|
|
|
112
112
|
That is the only executable stored plan. Do not copy an old workflow database
|
|
113
113
|
expecting old runs to resume; start new runs from current authored sources.
|
|
114
114
|
|
|
115
|
+
## Storage relocations within the 0.9.x line
|
|
116
|
+
|
|
117
|
+
0.9.11 (itlackey/akm#890) moves five machine-local `akm improve` writers out
|
|
118
|
+
of `$STASH/.akm` — where they never belonged, per the "must travel with the
|
|
119
|
+
content" rule in [Storage locations](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/storage-locations.md)
|
|
120
|
+
— into `$STATE`/`$CACHE`, namespaced per stash so two stashes on one machine
|
|
121
|
+
never collide:
|
|
122
|
+
|
|
123
|
+
| Old path | New path |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `$STASH/.akm/distill-rejected/` | `$STATE/improve/distill-rejected/<stash>/` |
|
|
126
|
+
| `$STASH/.akm/eval-cases/` | `$STATE/improve/eval-cases/<stash>/` |
|
|
127
|
+
| `$STASH/.akm/measurement/verdicts/` | `$STATE/improve/measurement/verdicts/<stash>/` |
|
|
128
|
+
| `$STASH/.akm/unresolved-sources/` | `$CACHE/index/unresolved-sources/<stash>/` |
|
|
129
|
+
| `$STASH/.akm/improve.lock` (+ `.improve.lock.operations.sensitive`) | `$STATE/locks/<stash>/improve.lock` (+ `.improve.lock.operations.sensitive`) |
|
|
130
|
+
|
|
131
|
+
Any script that reads the old paths directly — `scripts/akm-eval/src/proactive-verdict.ts`
|
|
132
|
+
(verdicts), `scripts/akm-eval/README.md`'s eval-cases note, or a custom
|
|
133
|
+
snapshot/backup tool — must read the new ones instead; the pilot treatment
|
|
134
|
+
file at `$STASH/.akm/measurement/` (sibling to `verdicts/`) is unaffected, it
|
|
135
|
+
was never a writer output. `akm migrate status`/`apply [--dry-run]` covers
|
|
136
|
+
every configured LOCAL bundle (the default stash first, then every other
|
|
137
|
+
filesystem-backed bundle — a `git`/`website`/`npm` bundle is cache-backed,
|
|
138
|
+
never touched), and reports and relocates any files still sitting at the old
|
|
139
|
+
paths (same-filesystem rename, or copy-then-delete across filesystems). A
|
|
140
|
+
lock file is only ever deleted once the same staleness check `akm improve`
|
|
141
|
+
itself uses says its holder is dead; a lock a live run still holds (or one
|
|
142
|
+
this process cannot read) is left in place and reported instead. The whole
|
|
143
|
+
step is idempotent — a second run reports nothing pending.
|
|
144
|
+
`$STASH/.akm/memory-cleanup/` did not move; it is the one confirmed exception
|
|
145
|
+
to the rule (see Storage locations, above).
|
|
146
|
+
|
|
115
147
|
## Recovery
|
|
116
148
|
|
|
117
149
|
If the new setup is wrong, stop AKM, move the new current directories aside,
|
|
@@ -303,6 +303,26 @@ one akm version reading a given `state.db` at a time; do not alternate
|
|
|
303
303
|
versions against the same state directory, and do not downgrade below
|
|
304
304
|
0.9.2 once a 0.9.2-or-later akm has recorded task history there.
|
|
305
305
|
|
|
306
|
+
## Harness id rename: `claude-code` -> `claude`
|
|
307
|
+
|
|
308
|
+
0.9.2 also renamed the Claude Code harness id from `claude-code` to
|
|
309
|
+
`claude` — the id used for both agent dispatch and the per-session
|
|
310
|
+
extraction ledger (`state.db`'s `extract_sessions_seen.harness` and
|
|
311
|
+
`workflow_runs.agent_harness`). The 0.9.2 release did not carry a state
|
|
312
|
+
migration for this rename, so any row a pre-0.9.2 akm wrote stayed
|
|
313
|
+
keyed under `claude-code`, invisible to anything querying by the new
|
|
314
|
+
name — a script or dashboard filtering `extract_sessions_seen` or
|
|
315
|
+
`workflow_runs` on `harness = 'claude-code'` (or
|
|
316
|
+
`agent_harness = 'claude-code'`) sees those rows disappear from that
|
|
317
|
+
query, not deleted, once you're on a release carrying the 0.9.12 fix.
|
|
318
|
+
0.9.12 adds state migration
|
|
319
|
+
`027-extract-sessions-seen-harness-rename`, which runs automatically
|
|
320
|
+
on the next managed `state.db` open (no separate command needed) and
|
|
321
|
+
renames every such row to `claude` in place — conflict-tolerant
|
|
322
|
+
against a session already recorded under `claude`, which is kept as
|
|
323
|
+
the authoritative row. After upgrading to 0.9.12 or later, re-point
|
|
324
|
+
any external query at `harness = 'claude'` / `agent_harness = 'claude'`.
|
|
325
|
+
|
|
306
326
|
## Workflow cutover
|
|
307
327
|
|
|
308
328
|
Markdown `.md` and GitHub-shaped `.yml` are peer workflow source formats in
|
package/docs/reference/cli.md
CHANGED
|
@@ -113,6 +113,14 @@ The `hint` field is present only when actionable remediation is available
|
|
|
113
113
|
`ok === false` on the parsed stderr envelope or a non-zero exit code to
|
|
114
114
|
detect failure. Scripts can rely on the exit code alone.
|
|
115
115
|
|
|
116
|
+
Every success envelope produced by the passthrough stamp — `config`, `clone`,
|
|
117
|
+
`models`, `task-*`, `workflow-*`, `registry-*`, and the rest of that shared
|
|
118
|
+
handler — also carries `ok: true` (0.9.12+), so a caller branching on `.ok`
|
|
119
|
+
sees the same field on both sides — success and failure — instead of
|
|
120
|
+
`undefined` on success. A command that already computes its own `ok` from a
|
|
121
|
+
graded outcome (e.g. `task run`'s exit-code mapping, `akm lint`, `akm proposal
|
|
122
|
+
extract`) keeps that value, `false` included.
|
|
123
|
+
|
|
116
124
|
`env run`, `secret run`, and `migrate` preserve the spawned process's exact
|
|
117
125
|
status and raw streams instead of replacing them with an akm failure envelope.
|
|
118
126
|
`task run` maps completed, active, and disabled status to 0; blocked and failed
|
|
@@ -272,17 +280,21 @@ akm health --report --window-compare 7d --format html
|
|
|
272
280
|
| `--window-compare` | Compare the current window against the prior window of the same duration (e.g. `24h`, `7d`). With `--report`, overrides the default trend window. |
|
|
273
281
|
| `--group-by` | Group rows by `run` (one row per `improve_runs` entry). Omit for the default summary. |
|
|
274
282
|
| `--windows` | Explicit comparison window(s) as `name=...,since=ISO,until=ISO` (repeatable, up to 4). Mutually exclusive with `--window-compare`. |
|
|
283
|
+
| `--no-probe` | Skip the `default-llm-engine` / `configured-engines` reachability probes (for an offline or air-gapped host). |
|
|
275
284
|
|
|
276
285
|
The command reads `state.db`, verifies that the required tables exist, performs a
|
|
277
286
|
write-read probe against the events stream, inspects `task_history`, checks the
|
|
278
|
-
default agent engine, and summarizes recent `improve_*` events.
|
|
287
|
+
default agent engine, and summarizes recent `improve_*` events. Unless
|
|
288
|
+
`--no-probe` is given, it also sends a bounded (3s timeout) reachability probe
|
|
289
|
+
to the `default-llm-engine` and every `configured-engines` LLM connection (and
|
|
290
|
+
an SDK engine's LLM fallback), one probe per distinct endpoint.
|
|
279
291
|
|
|
280
292
|
Primary result fields:
|
|
281
293
|
|
|
282
294
|
| Field | Description |
|
|
283
295
|
| --- | --- |
|
|
284
296
|
| `status` | Overall health verdict: `pass`, `warn`, or `fail` |
|
|
285
|
-
| `hardChecks` | Deterministic checks such as `state-db-schema`, `state-db-round-trip`, `state-db-migrations`, `task-log-backing`, `active-runs`, `default-engine`,
|
|
297
|
+
| `hardChecks` | Deterministic checks such as `state-db-schema`, `state-db-round-trip`, `state-db-migrations`, `task-log-backing`, `active-runs`, `default-engine`, `model-map-files`, `default-llm-engine`, `configured-engines`, and `active-improve-strategy` |
|
|
286
298
|
| `advisories` | Non-fatal warnings including `semantic-search-runtime` and `session-extraction` (akmExtract pipeline health) |
|
|
287
299
|
| `metrics` | Aggregate task/runtime metrics: `taskFailRate`, `agentFailureRate`, `stuckActiveRuns`, `logBackingRate`, `probeRoundTripMs` |
|
|
288
300
|
| `improve` | Recent improve-loop counts derived from `improve_invoked`, `improve_skipped`, and `improve_completed` events |
|
|
@@ -300,9 +312,21 @@ holds a pending historical-destructive migration and something other than
|
|
|
300
312
|
`akm upgrade` / `akm migrate apply` opens it directly. Read this check's
|
|
301
313
|
`status` instead of grepping akm's error text for that case.
|
|
302
314
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
315
|
+
`default-llm-engine` and `configured-engines` probe reachability (not just
|
|
316
|
+
configuration) for a `kind: "llm"` engine — an unreachable endpoint is a hard
|
|
317
|
+
`fail` for `default-llm-engine` and a `warn` for any other engine. `--no-probe`
|
|
318
|
+
skips this. `active-improve-strategy` names the resolved engine per process
|
|
319
|
+
in its evidence and message, so a strategy-level `engine` pin that shadows
|
|
320
|
+
`defaults.llmEngine` is visible without config archaeology.
|
|
321
|
+
|
|
322
|
+
The `session-extraction` advisory is derived from the `extract_sessions_seen`
|
|
323
|
+
ledger for the last 7 days — not `improve_runs`, which the hook-driven `akm
|
|
324
|
+
proposal extract --session-id ...` invocation never writes. It reports
|
|
325
|
+
`unknown` when nothing was recorded in the window (cannot tell "off on
|
|
326
|
+
purpose" from "broken"), `warn` when every session in the window was skipped
|
|
327
|
+
for an infrastructure reason (`llm_unavailable`, `read_failed`, `exception`,
|
|
328
|
+
`locked_concurrent`) — naming the reason and, when recorded, the engine — and
|
|
329
|
+
`pass` otherwise, with per-outcome counts.
|
|
306
330
|
|
|
307
331
|
The indexed entity graph (entities/relations extracted from bundle assets) has
|
|
308
332
|
no dedicated inspection command; its summary counts surface as an info-level
|
|
@@ -568,8 +592,10 @@ akm workflow create ship-release
|
|
|
568
592
|
akm workflow create ship-release --from ./ship-release.md
|
|
569
593
|
akm workflow run workflows/ship-release --version 1.2.3
|
|
570
594
|
akm workflow run <run-id> # continue an active partial run
|
|
595
|
+
akm workflow run workflows/ship-release --new # start a fresh run even if one is already active
|
|
571
596
|
akm workflow status <run-id>
|
|
572
597
|
akm workflow status workflows/ship-release
|
|
598
|
+
akm workflow status 7c115132 # 8+ char run-id prefix also works
|
|
573
599
|
akm workflow resume <run-id>
|
|
574
600
|
akm workflow abandon <run-id>
|
|
575
601
|
akm workflow list --active
|
|
@@ -585,13 +611,21 @@ Subcommands:
|
|
|
585
611
|
| Subcommand | Description |
|
|
586
612
|
| --- | --- |
|
|
587
613
|
| `create <name>` | Validate and write a Markdown workflow under `workflows/`. `--path <dir>` places it in a subdirectory; `--from <file>` imports content; `--force` (requires `--from` or `--reset`) overwrites; `--print` prints the template that would be written instead of writing it |
|
|
588
|
-
| `run <run-id\|ref>` | Stable canonical start/resume/execute command. A ref starts a run or
|
|
614
|
+
| `run <run-id\|ref>` | Stable canonical start/resume/execute command. A ref starts a run or resumes the active run in the current scope (announced as `resumed: true`, see below); a run id continues that exact active run. `--new` starts a fresh run even when one is already active. Executes until completion, failure, verification rejection, interruption, or an explicit limit |
|
|
589
615
|
| `status <run-id\|ref>` | Show the full run state, including all step statuses. `--units` also lists per-unit rows from the run journal (diagnostics only). Renders a `children:` tree when the run composes child workflows |
|
|
590
616
|
| `list` | List workflow runs (optionally filtered by `--ref`; `--active` shows only `status=active` runs, excluding `blocked`/`failed`/`completed`). Child workflow runs are excluded unless `--children` is passed |
|
|
591
617
|
| `resume <run-id>` | Flip a `blocked` or `failed` run back to `active`. Completed runs cannot be resumed |
|
|
592
618
|
| `abandon <run-id>` | Mark a run failed so it stops counting as active (`resume` can reopen it) |
|
|
593
619
|
| `plan <ref>` | **Evolving.** Compile and freeze a workflow WITHOUT publishing a run: the canonical step graph, per-step frozen target kinds, task/child expansion, input bindings, source read set, and lowering notices — zero durable writes. Returns the full JSON envelope by default, like every other command; pass `--format text` for a human-readable summary |
|
|
594
620
|
|
|
621
|
+
Everywhere a run id is accepted (`run`, `status`, `resume`, `abandon`), a
|
|
622
|
+
unique run-id **prefix** of 8 or more characters works too — the same
|
|
623
|
+
convention `akm proposal accept`/`reject` use for proposal UUIDs. A prefix
|
|
624
|
+
matching more than one run is a usage error listing every candidate; a
|
|
625
|
+
prefix matching none is a not-found error. Only strings shaped like a run id
|
|
626
|
+
(hex digits and hyphens, 8+ characters) are ever treated as a prefix, so a
|
|
627
|
+
workflow ref is never mistaken for one.
|
|
628
|
+
|
|
595
629
|
The public `workflow start`, `next`, and `complete` lifecycle was removed in
|
|
596
630
|
0.9, along with the experimental `brief`/`report` external-driver protocol.
|
|
597
631
|
Use `workflow run` for execution and `workflow status` for inspection. The
|
|
@@ -633,6 +667,14 @@ The old `--params <json>` bag is removed.
|
|
|
633
667
|
| `--max-steps <n>` | Stop once this many steps have finished, leaving a partial run active. Must be at least 1. |
|
|
634
668
|
| `--max-retries <n>` | When a step fails, reopen the same run and retry the failed step up to this many additional times. Range: 0 through 100; default 0. Gate rejection and interruption are not retried. |
|
|
635
669
|
| `--timeout <duration>` | Abort the whole invocation after `N`, `Nms`, `Ns`, or `Nm`; bare `N` is milliseconds. The active step remains resumable. |
|
|
670
|
+
| `--new` | Start a fresh run even when one is already active for this ref, instead of resuming it. The existing active run is left untouched — it is never abandoned automatically. A workflow ref only: passing a run id with `--new` is a usage error (exit 2). Parameter flags are allowed together with `--new`, since it is starting a new run. |
|
|
671
|
+
|
|
672
|
+
**Resuming an active run is announced, not silent.** Passing a ref that
|
|
673
|
+
already has an active run in the current scope resumes that run rather than
|
|
674
|
+
starting a new one (unchanged since #485) — but the envelope now carries
|
|
675
|
+
`resumed: true` alongside the resumed run's `run.id`, and the default text
|
|
676
|
+
output leads with `resuming existing run <id> for <ref>; pass --new to start
|
|
677
|
+
a fresh run`. Pass `--new` to start a second, independent run instead.
|
|
636
678
|
|
|
637
679
|
The result includes the current `run`, an `executed` step report list, a
|
|
638
680
|
`stepsProcessed` count of the steps that finished, and optional `done`,
|
|
@@ -668,7 +710,7 @@ repos or directories. akm resolves that context from the nearest `.akm/config.js
|
|
|
668
710
|
ancestor when present, otherwise the nearest git root, otherwise the bundle root
|
|
669
711
|
when the cwd is inside it, otherwise the cwd itself. In practice this means:
|
|
670
712
|
|
|
671
|
-
- `workflow run workflows/<name>`
|
|
713
|
+
- `workflow run workflows/<name>` resumes the active run for the current project/worktree/directory (announced with `resumed: true`), or starts one when none is active. `--new` always starts a fresh run.
|
|
672
714
|
- `workflow status workflows/<name>` resolves the most-recently-updated run in the current scope only.
|
|
673
715
|
- `workflow list` shows runs for the current scope only.
|
|
674
716
|
- Direct run-id commands like `workflow status <run-id>` still work even if the run was started from another directory.
|
|
@@ -714,11 +756,12 @@ akm workflow status workflows/ship-release
|
|
|
714
756
|
akm workflow status <run-id> --units # also list per-unit rows from the run journal
|
|
715
757
|
```
|
|
716
758
|
|
|
717
|
-
Accepts
|
|
718
|
-
to the most-recently-updated run for that
|
|
719
|
-
`--units` adds per-unit rows (unit id,
|
|
720
|
-
result/error diagnostic text) from the run
|
|
721
|
-
evidence stays deterministic and is
|
|
759
|
+
Accepts a run id, a unique 8+ character run-id prefix, or a workflow ref.
|
|
760
|
+
When given a workflow ref, resolves to the most-recently-updated run for that
|
|
761
|
+
ref in the current working scope. `--units` adds per-unit rows (unit id,
|
|
762
|
+
status, failure reason, and any result/error diagnostic text) from the run
|
|
763
|
+
journal — diagnostics only; step evidence stays deterministic and is
|
|
764
|
+
unaffected.
|
|
722
765
|
|
|
723
766
|
#### workflow plan
|
|
724
767
|
|
|
@@ -1517,13 +1560,14 @@ Subcommands:
|
|
|
1517
1560
|
| --- | --- |
|
|
1518
1561
|
| `get <key>` | Read one config key |
|
|
1519
1562
|
| `list` | List current configuration |
|
|
1520
|
-
| `set <key> <value>` | Set one config key |
|
|
1521
|
-
| `unset <key>` | Unset an optional key, or a whole `embedding`/engine section |
|
|
1563
|
+
| `set <key> <value>` | Set one config key; prints the resulting config with `ok: true` |
|
|
1564
|
+
| `unset <key>` | Unset an optional key, or a whole `embedding`/engine section; prints the resulting config with `ok: true` |
|
|
1522
1565
|
| `path` | Show paths to config, bundle, cache, and index. `--all` prints every path; without it, just the config path. Load-bearing: `config path` is the one subcommand the CLI still allows to run when the on-disk config itself fails to load, so you always have a way to locate a broken config. |
|
|
1523
1566
|
|
|
1524
|
-
`set` and `unset` accept `--silent` to suppress the post-write config dump
|
|
1525
|
-
|
|
1526
|
-
and CI
|
|
1567
|
+
`set` and `unset` accept `--silent` to suppress the post-write config dump
|
|
1568
|
+
entirely — nothing is printed on stdout, and the exit code is the status (the
|
|
1569
|
+
write still happens and errors still print) — use it from hooks and CI
|
|
1570
|
+
scripts.
|
|
1527
1571
|
|
|
1528
1572
|
> **Removed in 0.9.0:** `akm config enable`/`akm config disable`. Use
|
|
1529
1573
|
> `akm registry add|remove` to toggle a registry, the general mechanism.
|
|
@@ -2253,6 +2297,19 @@ schedule) is the answer.
|
|
|
2253
2297
|
Requires an LLM engine: pass `--engine`, select a `--strategy` whose
|
|
2254
2298
|
`processes.extract.engine` is set, or configure `defaults.llmEngine`.
|
|
2255
2299
|
|
|
2300
|
+
**Output.** `ok` means the command ran to completion — it is `true` even when
|
|
2301
|
+
every session was skipped (an unreachable LLM engine included); it does not
|
|
2302
|
+
mean anything was harvested. Consumers that need "did this run actually
|
|
2303
|
+
harvest" branch on `skipReasons`, `warnings`, or `sessionsProcessed` /
|
|
2304
|
+
`sessionsSkipped` instead. The envelope also reports:
|
|
2305
|
+
|
|
2306
|
+
| Field | Description |
|
|
2307
|
+
| --- | --- |
|
|
2308
|
+
| `engine` | Resolved LLM engine name for this run. Absent only when extract is disabled by the selected improve strategy (the run returns before an engine is resolved). |
|
|
2309
|
+
| `engineKind` | `"llm"`, `"sdk"`, or `"agent"` — the kind of runner `engine` resolved to. Same absence condition as `engine`. |
|
|
2310
|
+
| `skipReasons` | Per-`skipReason` count across `sessions[]` (e.g. `{ "llm_unavailable": 25 }`). Present only when `sessionsSkipped > 0`. |
|
|
2311
|
+
| `warnings` | Includes one aggregate line per infrastructure skip reason that fired (`llm_unavailable`, `read_failed`, `exception`, `locked_concurrent`) — e.g. `25 of 25 sessions skipped: llm_unavailable (engine "default")` — so an engine outage is visible without inspecting `sessions[]`. Session-content skips (`already_extracted`, `too_short`, `triaged_out`) are counted in `skipReasons` but never produce a warning line. |
|
|
2312
|
+
|
|
2256
2313
|
#### proposal new
|
|
2257
2314
|
|
|
2258
2315
|
Generate a brand-new asset proposal from a description. Output is always a
|
|
@@ -2457,10 +2514,10 @@ shell commands. It manages on-disk task definitions under
|
|
|
2457
2514
|
(cron / launchd / schtasks). Task source v4 YAML (`version: 4`) is the only
|
|
2458
2515
|
executable source contract this release accepts; `akm task add` writes v4 —
|
|
2459
2516
|
see the canonical [Tasks reference](tasks.md). The
|
|
2460
|
-
group is `add | run | explain | sync | doctor | history | prune`
|
|
2461
|
-
no `list` or `remove`; use `akm search --type task` /
|
|
2462
|
-
to inspect, and edit the file + `akm task sync` to
|
|
2463
|
-
schedule.
|
|
2517
|
+
group is `add | run | explain | validate | sync | doctor | history | prune`
|
|
2518
|
+
— there is no `list` or `remove`; use `akm search --type task` /
|
|
2519
|
+
`akm show tasks/<id>` to inspect, and edit the file + `akm task sync` to
|
|
2520
|
+
change or remove a schedule.
|
|
2464
2521
|
|
|
2465
2522
|
```sh
|
|
2466
2523
|
akm search --type task # List tasks (cross-bundle)
|
|
@@ -2472,6 +2529,7 @@ akm task add nightly --schedule "@daily" --command "akm improve" --disabled # r
|
|
|
2472
2529
|
akm task add nightly --schedule "@daily" --command "akm improve" --force # overwrite an existing task id
|
|
2473
2530
|
akm task run <id> # Execute now (what the scheduler calls)
|
|
2474
2531
|
akm task explain <ref> # Read-only: declared inputs, target, schedule — spawns nothing
|
|
2532
|
+
akm task validate <path> # Read-only: parse one task file by path, report sync's diagnostic
|
|
2475
2533
|
akm task history [<id>] [--id <id>] [--limit <n>] # Recent runs from state.db (positional id == --id)
|
|
2476
2534
|
akm task sync # Reconcile on-disk YAML with scheduler
|
|
2477
2535
|
akm task sync --dry-run # Preview the reconcile — zero scheduler writes
|
|
@@ -2494,6 +2552,30 @@ it never spawns anything, writes history, or touches the scheduler. A
|
|
|
2494
2552
|
secret-shaped value prints as `<redacted>`. See
|
|
2495
2553
|
[`akm task explain`](tasks.md#akm-task-explain).
|
|
2496
2554
|
|
|
2555
|
+
`akm task validate <path>` parses ONE task file by filesystem path — not a
|
|
2556
|
+
concept ref or id, and the file need not live in any configured bundle —
|
|
2557
|
+
and reports the same diagnostic `akm task sync` would produce for it,
|
|
2558
|
+
INCLUDING sync's own cron-dialect check and its per-schedule-entry
|
|
2559
|
+
input-contract check (so a file `sync` would reject can never be reported
|
|
2560
|
+
`valid`/`converts` here): `{ok, path, sourceVersion, outcome, reason?,
|
|
2561
|
+
resolved?}` where `outcome` is `valid` (parses as task source v4 directly
|
|
2562
|
+
and passes both sync checks), `converts` (task v2/v3 that the deterministic
|
|
2563
|
+
migrator converts in memory and which then also passes both sync checks),
|
|
2564
|
+
`blocked` (task v2/v3 the migrator itself cannot convert — needs a human
|
|
2565
|
+
decision), `invalid` (the YAML doesn't parse, or the document fails schema
|
|
2566
|
+
validation, or it parsed but fails one of the two sync checks), or
|
|
2567
|
+
`not-a-task` (the YAML parses but never declares a `version:` field — not
|
|
2568
|
+
shaped like a task source). `resolved` is the compiled task shape
|
|
2569
|
+
`akm task sync` itself would build a scheduler binding from — id, the
|
|
2570
|
+
compiled schema version, resolved `uses`/`run` target, declared `inputs`
|
|
2571
|
+
contract, and `schedule` bindings — present only on `valid`/`converts`.
|
|
2572
|
+
Unlike `akm task explain`, it never runs execution lowering: a command-kind
|
|
2573
|
+
task validates the same whether or not the local config has an engine
|
|
2574
|
+
configured. Exits 0 for `valid`/`converts`, 1 for
|
|
2575
|
+
`blocked`/`invalid`/`not-a-task`, 2 for a missing or unreadable path.
|
|
2576
|
+
**Read-only**: it never touches the scheduler and never requires the file to
|
|
2577
|
+
be indexed or wired into a bundle.
|
|
2578
|
+
|
|
2497
2579
|
`akm task run` is what cron / launchd / schtasks invoke at the scheduled
|
|
2498
2580
|
time. Each run is recorded as a row in the durable `task_history` table
|
|
2499
2581
|
(`state.db`), surfaced by `akm task history` — **not** by `akm log`; there is
|
|
@@ -2539,7 +2621,8 @@ the AKM storage path or installed runtime path therefore requires an explicit
|
|
|
2539
2621
|
operates on the primary/default bundle. `add`, `history`, `sync`, `run`, and
|
|
2540
2622
|
`explain` all accept `--bundle <bundle>` to schedule, reconcile, or inspect
|
|
2541
2623
|
tasks that live in another configured bundle (`doctor` reports scheduler-wide
|
|
2542
|
-
state and takes no `--bundle`
|
|
2624
|
+
state and takes no `--bundle`; `validate` takes a bare filesystem path
|
|
2625
|
+
instead of a ref, so it has no bundle to target either):
|
|
2543
2626
|
|
|
2544
2627
|
```sh
|
|
2545
2628
|
akm task add nightly --schedule "@daily" --command "akm improve" --bundle team-bundle
|
|
@@ -217,7 +217,8 @@ and is never rescued by that fallback.
|
|
|
217
217
|
Index passes select engines through `index.defaults.engine` or
|
|
218
218
|
`index.<pass>.engine`. Per-pass `model`, `timeoutMs`, and `llm` fields are
|
|
219
219
|
invocation overrides; `enabled: false` disables that pass. Connection fields
|
|
220
|
-
such as `endpoint`, `provider`, and `
|
|
220
|
+
such as `endpoint`, `provider`, `apiKey`, and `apiKeyFile` belong only on
|
|
221
|
+
named engines.
|
|
221
222
|
|
|
222
223
|
`workflow.maxConcurrency` is the native workflow engine ceiling. An explicit
|
|
223
224
|
value is clamped to `1..64`. When absent, AKM derives the cap once from the CPU
|
|
@@ -494,7 +495,7 @@ generic walker.
|
|
|
494
495
|
| `AKM_BUNDLE_DIR` | Override the bundle directory |
|
|
495
496
|
| `AKM_DATA_DIR` | Override the data directory — `index.db`, durable `state.db`, and `akm.lock` (or set `XDG_DATA_HOME`) |
|
|
496
497
|
| `AKM_CACHE_DIR` | Override the cache directory — regenerable caches (or set `XDG_CACHE_HOME`) |
|
|
497
|
-
| `AKM_STATE_DIR` | Override the state directory — task-scheduler invocation state (or set `XDG_STATE_HOME`) |
|
|
498
|
+
| `AKM_STATE_DIR` | Override the state directory — task-scheduler invocation state, and (per stash) `akm improve`'s machine-local writers and whole-run lock (or set `XDG_STATE_HOME`) |
|
|
498
499
|
| `AKM_SQLITE_JOURNAL_MODE` | SQLite journal mode: `WAL` (default), `DELETE`, or `TRUNCATE` |
|
|
499
500
|
| `AKM_VERBOSE` | Truthy value enables the same diagnostics as `--verbose` |
|
|
500
501
|
| `AKM_DEBUG` | `1` prints a stack trace on unexpected internal errors |
|
|
@@ -503,6 +504,15 @@ For an engine named `fast`, its fallback variable is
|
|
|
503
504
|
`AKM_ENGINE_FAST_API_KEY`. An explicit `apiKey` symbolic reference is
|
|
504
505
|
authoritative and does not fall through to another variable.
|
|
505
506
|
|
|
507
|
+
`engines.<name>.apiKeyFile` is a file-backed alternative to `apiKey`, for a
|
|
508
|
+
host that refuses to put secrets in the process environment (a container
|
|
509
|
+
runtime's mounted secret, for example). It is a plain filesystem path — `~`
|
|
510
|
+
expands to the home directory — read at dispatch time and trimmed of one
|
|
511
|
+
trailing newline; the raw path is safe to keep in `config.json` since it is
|
|
512
|
+
not itself a secret. Setting both `apiKey` and `apiKeyFile` on the same
|
|
513
|
+
engine is rejected. A missing, unreadable, or empty file fails the call
|
|
514
|
+
closed, naming the engine and path but never the file's content.
|
|
515
|
+
|
|
506
516
|
Use `AKM_SQLITE_JOURNAL_MODE=DELETE` or `TRUNCATE` when WAL is unavailable,
|
|
507
517
|
such as on some NFS/SMB mounts. With the default `WAL` setting, AKM detects a
|
|
508
518
|
network filesystem for the data directory and falls back to `DELETE`.
|
|
@@ -16,7 +16,7 @@ AKM adds no network destinations of its own. The requests it *does* make all go
|
|
|
16
16
|
2. **Registry metadata and bundle packages** from sources you explicitly configure (GitHub, npm, git remotes, websites) — those hosts receive the fetch/clone/crawl requests, and website sources receive requests for the pages you crawl.
|
|
17
17
|
3. **`akm upgrade`** — fetches the latest release from GitHub releases (GitHub sees the request).
|
|
18
18
|
4. **`akm setup`** — a single DNS lookup for `github.com` to decide whether to skip network-dependent steps (Ollama detection, remote embedding probes) when offline. No HTTP request is made by this probe; if it succeeds, akm proceeds with the network-dependent steps you already configured.
|
|
19
|
-
5. **`akm improve` dead-link checks** — a full-scope improve run (the default for a bare `akm improve`) sends best-effort `HEAD` requests (following redirects, with a short timeout
|
|
19
|
+
5. **`akm improve` dead-link checks** — a full-scope improve run (the default for a bare `akm improve`) sends best-effort `HEAD` requests (following redirects, with a short per-request timeout, checked at a bounded concurrency rather than all at once) to every URL found in the bodies of the knowledge assets it is improving, to flag dead links. The hosts of those URLs see a `HEAD` request; no asset content is sent. Keep URLs you don't want probed out of knowledge-asset bodies, or run improve with an explicit narrower scope.
|
|
20
20
|
|
|
21
21
|
In every case the receiving endpoint is one you configured or invoked; the data leaving your machine is the data you directed AKM to send there.
|
|
22
22
|
|
package/docs/reference/tasks.md
CHANGED
|
@@ -385,6 +385,14 @@ for full before/after examples and recovery guidance.
|
|
|
385
385
|
- `akm task explain <ref>` prints a task's declared inputs, resolved target,
|
|
386
386
|
effective execution settings, and schedule bindings without running
|
|
387
387
|
anything — see [`akm task explain`](#akm-task-explain) above.
|
|
388
|
+
- `akm task validate <path>` parses one task file by filesystem path (the
|
|
389
|
+
file need not live in a configured bundle) and reports the same
|
|
390
|
+
`valid`/`converts`/`blocked`/`invalid`/`not-a-task` diagnostic
|
|
391
|
+
`akm task sync` would produce for it — including sync's own cron-dialect
|
|
392
|
+
check and its per-schedule-entry input-contract check — without touching
|
|
393
|
+
the scheduler and without requiring a configured engine, even for a
|
|
394
|
+
command-kind task. The envelope's own `sourceVersion` field names the
|
|
395
|
+
file's originally declared schema version (2, 3, or 4).
|
|
388
396
|
- `akm task add` writes a task source v4 document and installs it after
|
|
389
397
|
validation. `--params` renders typed `inputs:` declarations instead of a
|
|
390
398
|
`with:` bag; `--schedule` is required on every invocation, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
|
|
6
6
|
"keywords": [
|