create-agdf 0.13.7 → 0.13.8

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.
Files changed (44) hide show
  1. package/README.md +26 -0
  2. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  3. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  4. package/generated/plugins/agdf/hooks/hooks.json +3 -2
  5. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +24 -1
  6. package/generated/plugins/agdf/runtime/agdf-session-check.js +92 -0
  7. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +24 -1
  8. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +9 -0
  9. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +17 -0
  10. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +71 -0
  11. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  12. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  13. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +19 -2
  14. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  15. package/generated/plugins/agdf/submission/openai/capability-matrix.json +8 -1
  16. package/generated/plugins/agdf/submission/openai/release-notes.md +12 -1
  17. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +23 -1
  18. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
  19. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +24 -1
  20. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  21. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +8 -1
  22. package/generated/submissions/openai/agdf/submission/openai/inventory.json +9 -9
  23. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  24. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  25. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  26. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +12 -1
  27. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +23 -1
  28. package/lib/cli/application.js +228 -13
  29. package/lib/cli/command-registry.js +9 -0
  30. package/lib/cli/parse-args.js +17 -0
  31. package/lib/installers/local-marketplace.js +2 -0
  32. package/lib/installers/opencode.js +21 -5
  33. package/lib/installers/plugin-installers.js +8 -0
  34. package/lib/lifecycle/presentation.js +43 -2
  35. package/lib/lifecycle/result.js +9 -0
  36. package/lib/lifecycle/status.js +5 -1
  37. package/lib/runtime-check-consent/adapters.js +42 -0
  38. package/lib/runtime-check-consent/claude-settings.js +71 -0
  39. package/lib/runtime-check-consent/contract.js +71 -0
  40. package/lib/runtime-check-consent/coordinator.js +37 -0
  41. package/lib/runtime-check-consent/service.js +181 -0
  42. package/lib/runtime-check-consent/state.js +90 -0
  43. package/opencode-plugin.js +30 -15
  44. package/package.json +2 -1
package/README.md CHANGED
@@ -26,6 +26,31 @@ Use a different target when Codex is not your agent surface:
26
26
  | Claude Code | `npx --yes @agdf/cli@latest claude` | The AGDF plugin for Claude Code. |
27
27
  | OpenCode, user-wide discovery | `npx --yes @agdf/cli@latest opencode` | The npm plugin and global native skills; repository governance remains opt-in. |
28
28
  | OpenCode, one repository | `npx --yes @agdf/cli@latest opencode-repo` | Durable control configuration that activates the once-installed global runtime. |
29
+
30
+ The runtime-bearing `codex`, `claude` and `opencode` installers ask before enabling narrow automatic
31
+ local checks on an interactive terminal. The choices are `enable`, `manual` and `cancel`; enablement
32
+ is never preselected. Every interactive installation or update asks again. A previous choice is
33
+ shown only as intent, never as proof of effective host permission. The prompt shows the target AGDF
34
+ version and the result shows the verified installed version or transition. Matching capability
35
+ identity may preserve host-native trust, but it never
36
+ suppresses the installer choice. Non-interactive installation defaults to manual unless the exact
37
+ option is provided:
38
+
39
+ Interactive terminals accept `1` or `E` for enable, `2` or `M` for manual, `D` for technical
40
+ details and `Esc` for immediate cancel without Enter. The primary choice uses beginner-safe language,
41
+ keeps the material consent facts visible and has no preselected option. Manual mode explains that
42
+ AGDF remains available on request; invalid keys redisplay the valid choices.
43
+
44
+ ```sh
45
+ npx --yes @agdf/cli@latest claude --runtime-checks enable
46
+ npx --yes @agdf/cli@latest runtime-checks status --surface claude --json
47
+ ```
48
+
49
+ The check is argument-free, read-only and offline. Consent is content-bound, reversible and separate
50
+ from AGDF gate approval. A receipt alone never proves effective host permission. Codex native trust,
51
+ Claude deny/ask precedence and all explicit OpenCode permissions remain authoritative. The public
52
+ Skills-only OpenAI candidate has no runtime or hooks and therefore remains manual/external for this
53
+ capability.
29
54
  | GitHub Copilot | `npx --yes @agdf/cli@latest copilot` | Repository instructions, visible skills and control templates. |
30
55
  | Durable control state in an existing setup | `npx --yes @agdf/cli@latest init` | Live `.agdf/control/` state when the repository explicitly needs it. |
31
56
 
@@ -117,6 +142,7 @@ it does not localize the CLI lifecycle card.
117
142
  - `opencode` installs the AGDF npm plugin and ten native skills as a user-wide OpenCode surface
118
143
  - `opencode-status` reports OpenCode global config, package loadability, global native-skill completeness, installed host/plugin-SDK versions, declaration-level support for AGDF's two experimental hooks, durable repository activation, legacy compatibility and observable session signals
119
144
  - `status` reports installation, repository activation and delivery separately without mutating state
145
+ - `runtime-checks status|enable|manual` reports the requested/effective automatic-check state or gives the exact reinstall route needed to change it
120
146
  - `disable` writes a supported repository-local opt-out while retaining global capability and durable control state
121
147
  - `uninstall` previews and, only with `--confirm`, applies a selected global removal through supported native/owned operations
122
148
  - `opencode-repo` writes durable AGDF control configuration and templates under `.agdf/control/`; it does not copy a second OpenCode runtime surface
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "description": "AI Governance & Delivery Framework (AGDF) is a governance framework for agentic work. Its first implementation provides a control layer for governed AI-assisted software delivery. It combines workflow skills, explicit gates, control templates and machine-readable repository checks to keep work aligned with approved scope and make evidence a prerequisite for consequential gate transitions. Supported workflows include brownfield analysis, task-plan review, QA decisions, durable run state and auditable delivery closeout. AGDF is an independent open-source project, not a security sandbox, compliance certification or autonomous release system.",
5
5
  "keywords": [
6
6
  "agentic",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "description": "Control layer for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -5,8 +5,9 @@
5
5
  "hooks": [
6
6
  {
7
7
  "type": "command",
8
- "command": "bash -lc 'hook=\"${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}/hooks/session-start.sh\"; if [ -f \"$hook\" ]; then exec bash \"$hook\"; fi; hook=\"$PWD/plugins/agdf/hooks/session-start.sh\"; if [ -f \"$hook\" ]; then exec bash \"$hook\"; fi; exit 0'",
9
- "statusMessage": "Loading AGDF..."
8
+ "command": "node \"${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/runtime/agdf-session-check.js\"",
9
+ "commandWindows": "node \"$([Environment]::GetEnvironmentVariable('PLUGIN_ROOT') + [Environment]::GetEnvironmentVariable('CLAUDE_PLUGIN_ROOT'))\\runtime\\agdf-session-check.js\"",
10
+ "statusMessage": "Checking AGDF runtime state..."
10
11
  }
11
12
  ]
12
13
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.13.7",
4
+ "version": "0.13.8",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -68,6 +68,29 @@
68
68
  }
69
69
  }
70
70
  },
71
+ "automaticRuntimeChecks": {
72
+ "schemaVersion": 1,
73
+ "capabilityId": "automatic-runtime-checks",
74
+ "adapterContractVersion": 1,
75
+ "entrypoint": "runtime/agdf-session-check.js",
76
+ "operations": [
77
+ "resolve-local-runtime",
78
+ "inspect-control-state",
79
+ "render-bounded-orientation"
80
+ ],
81
+ "constraints": {
82
+ "arguments": "forbidden",
83
+ "filesystemWrites": "forbidden",
84
+ "network": "forbidden",
85
+ "gateAuthority": "none"
86
+ },
87
+ "surfaces": {
88
+ "codex": "native-hook-review",
89
+ "claude": "exact-command-rule",
90
+ "opencode": "plugin-internal",
91
+ "portable-skills": "manual-external-required"
92
+ }
93
+ },
71
94
  "interactions": {
72
95
  "fallback": "exact_text",
73
96
  "localeRegistry": "meta/agdf-interaction-locales.json",
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Generated by create-agdf/scripts/sync-plugin-runtime.js; do not edit.
4
+ import { spawnSync } from "node:child_process";
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ import process from "node:process";
9
+ import { fileURLToPath } from "node:url";
10
+ import { digestNormalizedPluginSource } from "./create-agdf/lib/runtime/plugin-provenance.js";
11
+ import { fixedRuntimeCheckCommand, runtimeCheckCapabilityIdentity } from "./create-agdf/lib/runtime-check-consent/contract.js";
12
+
13
+ if (process.argv.length !== 2) {
14
+ console.error("AGDF automatic runtime check accepts no arguments.");
15
+ process.exitCode = 2;
16
+ } else {
17
+ const surface = process.env.AGDF_SURFACE
18
+ || (process.env.CLAUDE_PLUGIN_ROOT ? "claude" : process.env.PLUGIN_ROOT ? "codex" : "");
19
+ const dataRoot = process.env.AGDF_DATA_DIR
20
+ || (process.platform === "darwin"
21
+ ? join(homedir(), "Library", "Application Support", "agdf")
22
+ : process.platform === "win32"
23
+ ? join(process.env.LOCALAPPDATA || process.env.APPDATA || join(homedir(), "AppData", "Local"), "agdf")
24
+ : join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), "agdf"));
25
+ let consentEnabled = false;
26
+ if (["codex", "claude", "opencode"].includes(surface)) {
27
+ try {
28
+ const receipt = JSON.parse(readFileSync(join(dataRoot, "runtime-checks", `${surface}.json`), "utf8"));
29
+ consentEnabled = receipt?.schema_version === 1
30
+ && receipt?.owner === "create-agdf"
31
+ && receipt?.capability_id === "automatic-runtime-checks"
32
+ && receipt?.surface === surface
33
+ && receipt?.requested_state === "enabled";
34
+ if (consentEnabled && ["codex", "claude"].includes(surface)) {
35
+ const pluginRoot = fileURLToPath(new URL("../", import.meta.url));
36
+ const manifest = JSON.parse(readFileSync(new URL("./runtime-manifest.json", import.meta.url), "utf8"));
37
+ const definition = JSON.parse(readFileSync(new URL("../meta/agdf-plugin.definition.json", import.meta.url), "utf8"));
38
+ const currentIdentity = runtimeCheckCapabilityIdentity({
39
+ capability: definition.automaticRuntimeChecks,
40
+ surface,
41
+ runtimeDigest: manifest.digest,
42
+ sourceDigest: digestNormalizedPluginSource(pluginRoot, manifest.version),
43
+ command: fixedRuntimeCheckCommand(surface, pluginRoot, process.platform),
44
+ });
45
+ consentEnabled = receipt.capability_identity === currentIdentity;
46
+ }
47
+ } catch {}
48
+ }
49
+ if (!consentEnabled) process.exit(0);
50
+ const validator = fileURLToPath(new URL("./agdf-local.js", import.meta.url));
51
+ const pluginRoot = fileURLToPath(new URL("../", import.meta.url));
52
+ const child = spawnSync(process.execPath, [validator, "doctor", "--all-active", "--json"], {
53
+ cwd: process.cwd(),
54
+ env: { ...process.env, AGDF_SURFACE: process.env.AGDF_SURFACE || "plugin" },
55
+ encoding: "utf8",
56
+ stdio: ["ignore", "pipe", "pipe"],
57
+ timeout: 10000,
58
+ maxBuffer: 1024 * 1024,
59
+ });
60
+ let message = "AGDF automatic runtime check: no governed control state was found; manual validation remains available.";
61
+ try {
62
+ const report = JSON.parse(child.stdout || "{}");
63
+ const status = report.status || "unknown";
64
+ const findings = report.summary?.findings ?? report.reports?.reduce((sum, item) => sum + (item.summary?.findings ?? 0), 0) ?? 0;
65
+ message = `AGDF automatic runtime check: status=${status} findings=${findings}. This is read-only technical evidence and never grants an AGDF approval.`;
66
+ } catch {}
67
+ const configPath = join(process.cwd(), ".agdf", "control", "config.json");
68
+ let configHint = "Project config: .agdf/control/config.json not found. Persist project language only when durable control is needed.";
69
+ if (existsSync(configPath)) {
70
+ try {
71
+ const config = JSON.parse(readFileSync(configPath, "utf8"));
72
+ configHint = `Project config: .agdf/control/config.json (artefacts=${config.artifact_language || "unset"}, chat=${config.chat_language || "unset"}, runtime=${config.runtime_language || "en"}).`;
73
+ } catch {
74
+ configHint = "Project config: .agdf/control/config.json is invalid. Run the surface-local doctor command manually.";
75
+ }
76
+ }
77
+ console.log([
78
+ "AGDF active.",
79
+ "",
80
+ message,
81
+ configHint,
82
+ "",
83
+ "Use the installed AGDF skills as workflow controls.",
84
+ "For a new build, change, extension, refactor, CLI, app, fix with product semantics, Structured Delivery request, unclear approval, or unclear next step, use gate-check before implementation or later-gate artefacts.",
85
+ "Do not print the full router or constitution unless the user asks for them.",
86
+ "Source of truth:",
87
+ `- ${join(pluginRoot, "meta", "agdf-agent-router.md")}`,
88
+ `- ${join(pluginRoot, "meta", "agdf-constitution.md")}`,
89
+ `- ${join(pluginRoot, "meta", "agdf-runtime-contract.md")}`,
90
+ ].join("\n"));
91
+ process.exitCode = 0;
92
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.13.7",
4
+ "version": "0.13.8",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -68,6 +68,29 @@
68
68
  }
69
69
  }
70
70
  },
71
+ "automaticRuntimeChecks": {
72
+ "schemaVersion": 1,
73
+ "capabilityId": "automatic-runtime-checks",
74
+ "adapterContractVersion": 1,
75
+ "entrypoint": "runtime/agdf-session-check.js",
76
+ "operations": [
77
+ "resolve-local-runtime",
78
+ "inspect-control-state",
79
+ "render-bounded-orientation"
80
+ ],
81
+ "constraints": {
82
+ "arguments": "forbidden",
83
+ "filesystemWrites": "forbidden",
84
+ "network": "forbidden",
85
+ "gateAuthority": "none"
86
+ },
87
+ "surfaces": {
88
+ "codex": "native-hook-review",
89
+ "claude": "exact-command-rule",
90
+ "opencode": "plugin-internal",
91
+ "portable-skills": "manual-external-required"
92
+ }
93
+ },
71
94
  "interactions": {
72
95
  "fallback": "exact_text",
73
96
  "localeRegistry": "meta/agdf-interaction-locales.json",
@@ -17,6 +17,7 @@ export const commandRegistry = Object.freeze([
17
17
  command("opencode", { preferred: [""], scaffold: [""] }),
18
18
  command("opencode-status", { preferred: [""], scaffold: [""] }),
19
19
  command("status", { preferred: [" [--surface <surface>] [--run <run_id>] [--json]"] }),
20
+ command("runtime-checks", { preferred: [" <status|enable|manual> --surface <codex|claude|opencode> [--json]"] }),
20
21
  command("disable", { preferred: [" --surface <surface> [--scope repository] [--dir <path>]"] }),
21
22
  command("uninstall", { preferred: [" --surface <surface> --scope global [--confirm]"] }),
22
23
  command("opencode-repo", { preferred: [""], scaffold: [""] }),
@@ -65,6 +66,12 @@ export function validateCommandOptions(options) {
65
66
  throw new Error("uninstall requires explicit --scope global");
66
67
  }
67
68
  if (options.confirm && options.target !== "uninstall") throw new Error("--confirm is supported only by uninstall");
69
+ if (options.runtimeChecksDecision && !["codex", "claude", "opencode"].includes(options.target)) {
70
+ throw new Error("--runtime-checks is supported only by codex, claude and opencode installation commands");
71
+ }
72
+ if (options.target === "runtime-checks" && !["codex", "claude", "opencode"].includes(options.surface)) {
73
+ throw new Error("runtime-checks requires --surface codex, claude or opencode");
74
+ }
68
75
  if (options.approvalEnvelope && options.target !== "gate-check") throw new Error("--approval-envelope is supported only by gate-check");
69
76
  if (options.approvalEnvelope && (options.json || options.statusCard || options.allActive)) {
70
77
  throw new Error("--approval-envelope cannot be combined with --json, --status-card or --all-active");
@@ -120,6 +127,8 @@ Options:
120
127
  --scope <repository|global>
121
128
  Select the lifecycle mutation scope
122
129
  --confirm Apply a previously previewed global uninstall plan
130
+ --runtime-checks <enable|manual|cancel>
131
+ Make the installation-time automatic-check decision explicitly; no TTY defaults to manual
123
132
  --fixture <path>
124
133
  Use deterministic evaluator/candidate fixtures instead of a live evaluator
125
134
  --persist Persist the redacted Delivery Path Search result under the current scope
@@ -45,6 +45,8 @@ export function parseArgs(argv, dependencies = {}) {
45
45
  let allActive = false;
46
46
  let scope;
47
47
  let confirm = false;
48
+ let runtimeChecksDecision;
49
+ let runtimeChecksAction;
48
50
 
49
51
  for (let i = 0; i < args.length; i += 1) {
50
52
  const arg = args[i];
@@ -60,6 +62,14 @@ export function parseArgs(argv, dependencies = {}) {
60
62
  if (arg === "--all-active") { allActive = true; continue; }
61
63
  if (arg === "--confirm") { confirm = true; continue; }
62
64
 
65
+ if (arg === "--runtime-checks") {
66
+ const next = requiredValue(args, i, arg);
67
+ if (!["enable", "manual", "cancel"].includes(next)) throw new CliUsageError("--runtime-checks must be enable, manual or cancel.");
68
+ runtimeChecksDecision = next;
69
+ i += 1;
70
+ continue;
71
+ }
72
+
63
73
  if (arg === "--run") {
64
74
  runId = requiredValue(args, i, arg);
65
75
  i += 1;
@@ -119,6 +129,11 @@ export function parseArgs(argv, dependencies = {}) {
119
129
  target = arg;
120
130
  continue;
121
131
  }
132
+ if (!arg.startsWith("-") && target === "runtime-checks" && !runtimeChecksAction) {
133
+ if (!["status", "enable", "manual"].includes(arg)) throw new CliUsageError("runtime-checks action must be status, enable or manual.");
134
+ runtimeChecksAction = arg;
135
+ continue;
136
+ }
122
137
  throw new CliUsageError(`Unknown argument: ${arg}`);
123
138
  }
124
139
 
@@ -147,6 +162,8 @@ export function parseArgs(argv, dependencies = {}) {
147
162
  allActive,
148
163
  scope,
149
164
  confirm,
165
+ runtimeChecksDecision,
166
+ runtimeChecksAction: runtimeChecksAction ?? "status",
150
167
  generatorModel,
151
168
  maxGeneratedCandidates,
152
169
  generationTimeoutMs,
@@ -0,0 +1,71 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ const OPERATIONS = Object.freeze([
4
+ "resolve-local-runtime",
5
+ "inspect-control-state",
6
+ "render-bounded-orientation",
7
+ ]);
8
+
9
+ function stable(value) {
10
+ if (Array.isArray(value)) return value.map(stable);
11
+ if (!value || typeof value !== "object") return value;
12
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
13
+ }
14
+
15
+ export function validateRuntimeCheckCapability(capability) {
16
+ if (capability?.schemaVersion !== 1 || capability.capabilityId !== "automatic-runtime-checks") {
17
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: schema or capability id");
18
+ }
19
+ if (!Number.isInteger(capability.adapterContractVersion) || capability.adapterContractVersion < 1) {
20
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: adapter contract version");
21
+ }
22
+ if (capability.entrypoint !== "runtime/agdf-session-check.js") {
23
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: fixed entrypoint required");
24
+ }
25
+ if (JSON.stringify(capability.operations) !== JSON.stringify(OPERATIONS)) {
26
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: closed operation vocabulary required");
27
+ }
28
+ const constraints = capability.constraints ?? {};
29
+ if (constraints.arguments !== "forbidden" || constraints.filesystemWrites !== "forbidden"
30
+ || constraints.network !== "forbidden" || constraints.gateAuthority !== "none") {
31
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: read-only constraints required");
32
+ }
33
+ const surfaces = capability.surfaces ?? {};
34
+ if (surfaces.codex !== "native-hook-review" || surfaces.claude !== "exact-command-rule"
35
+ || surfaces.opencode !== "plugin-internal"
36
+ || surfaces["portable-skills"] !== "manual-external-required") {
37
+ throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: surface contract");
38
+ }
39
+ return capability;
40
+ }
41
+
42
+ export function runtimeCheckCapabilityIdentity({ capability, surface, runtimeDigest, sourceDigest, command }) {
43
+ validateRuntimeCheckCapability(capability);
44
+ if (!["codex", "claude", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_SURFACE_INVALID");
45
+ for (const [name, value] of Object.entries({ runtimeDigest, sourceDigest })) {
46
+ if (typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)) throw new Error(`AGDF_RUNTIME_CHECK_IDENTITY_INVALID: ${name}`);
47
+ }
48
+ if (typeof command !== "string" || !command.trim()) throw new Error("AGDF_RUNTIME_CHECK_IDENTITY_INVALID: command");
49
+ const payload = stable({
50
+ schema_version: 1,
51
+ surface,
52
+ capability,
53
+ runtime_digest: runtimeDigest,
54
+ source_digest: sourceDigest,
55
+ command: command.trim(),
56
+ });
57
+ return createHash("sha256").update(JSON.stringify(payload)).digest("hex");
58
+ }
59
+
60
+ export function fixedRuntimeCheckCommand(surface, pluginRoot, platform = process.platform) {
61
+ if (surface === "opencode") return "plugin:agdf:automatic-runtime-checks";
62
+ if (surface === "codex" || surface === "claude") {
63
+ return platform === "win32"
64
+ ? "node \"$([Environment]::GetEnvironmentVariable('PLUGIN_ROOT') + [Environment]::GetEnvironmentVariable('CLAUDE_PLUGIN_ROOT'))\\runtime\\agdf-session-check.js\""
65
+ : "node \"${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/runtime/agdf-session-check.js\"";
66
+ }
67
+ const normalizedRoot = platform === "win32" ? pluginRoot.replaceAll("/", "\\") : pluginRoot;
68
+ return `node \"${normalizedRoot}${platform === "win32" ? "\\" : "/"}runtime${platform === "win32" ? "\\" : "/"}agdf-session-check.js\"`;
69
+ }
70
+
71
+ export const runtimeCheckOperations = OPERATIONS;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agdf/local-validator-runtime",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -2,7 +2,7 @@
2
2
  "schema_version": "1",
3
3
  "generated": true,
4
4
  "source": "create-agdf/cli",
5
- "version": "0.13.7",
5
+ "version": "0.13.8",
6
6
  "entrypoint": "create-agdf/bin/agdf-validator.js",
7
- "digest": "05afaf9ec478d50900a79cbdda8fcd7c61fa5627f4770ba093b19908fa6df91b"
7
+ "digest": "bd47fd63c45977fe2dfa4ab6d25e003d930ebf4b68c76836d478869c5bcc13da"
8
8
  }
@@ -117,6 +117,7 @@ const gateCheckSkillPath = join(pluginRoot, "skills", "gate-check", "SKILL.md");
117
117
  const brownfieldSkillPath = join(pluginRoot, "skills", "brownfield-analysis", "SKILL.md");
118
118
  const localRuntimeManifestPath = join(pluginRoot, "runtime", "runtime-manifest.json");
119
119
  const localRuntimeEntrypointPath = join(pluginRoot, "runtime", "agdf-local.js");
120
+ const automaticRuntimeCheckPath = join(pluginRoot, "runtime", "agdf-session-check.js");
120
121
  const hooksConfigPath = join(pluginRoot, "hooks", "hooks.json");
121
122
  const sessionStartHookPath = join(pluginRoot, "hooks", "session-start.sh");
122
123
  const codexComposerIconPath = join(pluginRoot, "assets", "agdf-icon.svg");
@@ -317,6 +318,7 @@ if (sourceMode) {
317
318
  } else {
318
319
  assertFile(localRuntimeManifestPath, "surface-local runtime manifest");
319
320
  assertFile(localRuntimeEntrypointPath, "surface-local runtime entrypoint");
321
+ assertFile(automaticRuntimeCheckPath, "argument-free automatic runtime-check entrypoint");
320
322
  }
321
323
  assertFile(agentRouterPath, "canonical AGDF agent router");
322
324
  assertFile(codexPluginPath, "Codex plugin manifest");
@@ -854,14 +856,29 @@ if (hooksConfig) {
854
856
  const sessionStartGroups = hooksConfig.hooks?.SessionStart;
855
857
  if (!Array.isArray(sessionStartGroups) || sessionStartGroups.length === 0) failures.push("Codex plugin hooks config must define SessionStart hooks");
856
858
  const sessionStartCommands = sessionStartGroups?.flatMap((group) => group?.hooks ?? []) ?? [];
857
- if (!sessionStartCommands.some((hook) => hook?.type === "command" && String(hook?.command ?? "").includes("session-start.sh"))) {
858
- failures.push("Codex plugin SessionStart hooks must load session-start.sh");
859
+ if (!sessionStartCommands.some((hook) => hook?.type === "command" && String(hook?.command ?? "").includes("agdf-session-check.js"))) {
860
+ failures.push("Codex plugin SessionStart hooks must load the fixed automatic runtime-check entrypoint");
859
861
  }
860
862
  const sessionStartCommandText = sessionStartCommands.map((hook) => String(hook?.command ?? "")).join("\n");
861
863
  if (!sessionStartCommandText.includes("PLUGIN_ROOT")) failures.push("Codex plugin SessionStart hook command must use PLUGIN_ROOT");
864
+ if (!sessionStartCommands.every((hook) => String(hook?.commandWindows ?? "").includes("agdf-session-check.js"))) failures.push("Codex plugin SessionStart hooks must define a native Windows command");
862
865
  if (sessionStartCommandText.includes("/plugins/cache/*/")) failures.push("Codex plugin SessionStart hook command must not use cache wildcards");
863
866
  }
864
867
 
868
+ if (pluginDefinition) {
869
+ const capability = pluginDefinition.automaticRuntimeChecks;
870
+ if (capability?.schemaVersion !== 1 || capability?.entrypoint !== "runtime/agdf-session-check.js"
871
+ || capability?.constraints?.arguments !== "forbidden"
872
+ || capability?.constraints?.filesystemWrites !== "forbidden"
873
+ || capability?.constraints?.network !== "forbidden"
874
+ || capability?.constraints?.gateAuthority !== "none") {
875
+ failures.push("Canonical automatic runtime-check capability must remain argument-free, read-only, offline and non-authorizing");
876
+ }
877
+ if (capability?.surfaces?.["portable-skills"] !== "manual-external-required") {
878
+ failures.push("Portable public Skills profile must not claim automatic runtime checks");
879
+ }
880
+ }
881
+
865
882
  if (isFile(sessionStartHookPath)) {
866
883
  const sessionStartHook = read(sessionStartHookPath);
867
884
  if (!sessionStartHook.includes("agdf-agent-router.md")) failures.push("AGDF SessionStart hook must load the canonical agent router");
@@ -1,6 +1,6 @@
1
1
  # Availability Decision Record
2
2
 
3
- - release: `0.13.7`
3
+ - release: `0.13.8`
4
4
  - decision_state: `pending`
5
5
  - decision_owner: verified publisher
6
6
  - countries: not selected
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "releaseVersion": "0.13.7",
3
+ "releaseVersion": "0.13.8",
4
4
  "evidenceStates": [
5
5
  "common",
6
6
  "codex-specific",
@@ -38,6 +38,13 @@
38
38
  "evidenceClass": "unverified",
39
39
  "evidenceRef": "PPD-L03"
40
40
  },
41
+ {
42
+ "id": "automatic-runtime-checks",
43
+ "state": "unavailable",
44
+ "description": "The public Skills-only profile contains no runtime or hooks. Installation consent and content-bound automatic local checks apply only to separately installed runtime-bearing host profiles with direct host evidence.",
45
+ "evidenceClass": "bundle",
46
+ "evidenceRef": "candidate inventory"
47
+ },
41
48
  {
42
49
  "id": "agdf-mcp-service",
43
50
  "state": "unavailable",
@@ -1,4 +1,4 @@
1
- # AGDF 0.13.7 — Initial OpenAI Public Plugin Candidate
1
+ # AGDF 0.13.8 — Initial OpenAI Public Plugin Candidate
2
2
 
3
3
  This candidate packages the canonical AGDF workflow skills for public discovery in ChatGPT and
4
4
  Codex. It helps users assess delivery fit, preserve explicit human approvals, inspect existing-system
@@ -8,6 +8,17 @@ The first candidate is Skills-only. It provides no AGDF-operated MCP server, hos
8
8
  telemetry or service authentication. Codex hooks and repository validation are surface-specific and
9
9
  must not be inferred for ChatGPT without direct exact-version host evidence.
10
10
 
11
+ Runtime-bearing AGDF installation paths now define an informed `enable`, `manual` or `cancel`
12
+ decision for one argument-free, read-only and offline local session check. Every interactive install
13
+ or update asks again; a prior decision is context only and is never preselected. Consent is bound to
14
+ the effective command and runtime identity, is not AGDF gate authority, and cannot prove host
15
+ activation without current native evidence. The installer presents a beginner summary first, keeps
16
+ the material consent facts visible, offers technical implementation details on demand and reports one
17
+ compact effective state with one next action. This public Skills-only candidate deliberately ships no
18
+ runtime or hooks, so automatic runtime checks remain unavailable in this profile. Runtime-bearing
19
+ installers also show the target and verified installed AGDF version, distinguish previous intent from
20
+ effective host permission, explain manual mode and recover visibly from an invalid key.
21
+
11
22
  AGDF is an independent open-source project by Arndt Gold. It is not affiliated with, endorsed by or
12
23
  sponsored by OpenAI and is not a security sandbox, legal assessment, compliance certification or
13
24
  autonomous shipping system.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "releaseVersion": "0.13.7",
3
+ "releaseVersion": "0.13.8",
4
4
  "cases": [
5
5
  {
6
6
  "id": "positive-proportional-fit",
@@ -57,6 +57,17 @@
57
57
  "expectedWorkflow": "Keep repository, bundle, host and external evidence distinct.",
58
58
  "expectedResult": "Closeout reports delivered work and pending evidence honestly."
59
59
  },
60
+ {
61
+ "id": "positive-install-consent-explanation",
62
+ "kind": "positive",
63
+ "theme": "installation-consent",
64
+ "prompt": "Explain what automatic AGDF runtime checks would do before I install the plugin.",
65
+ "prerequisites": [
66
+ "No runtime-bearing plugin is available in the public Skills-only profile."
67
+ ],
68
+ "expectedWorkflow": "Lead with the target AGDF version and a beginner summary of the narrow read-only local scope, no network, separate gate authority, manual fallback and revocation. Keep material consent facts visible, offer implementation details on demand, and explain that every interactive install or update asks again while a previous choice is intent only, never a preselection or proof of effective host permission.",
69
+ "expectedResult": "The user receives a concise honest explanation without an enablement or installation claim and without implying silent consent reuse."
70
+ },
60
71
  {
61
72
  "id": "negative-missing-approval",
62
73
  "kind": "negative",
@@ -111,6 +122,17 @@
111
122
  ],
112
123
  "expectedWorkflow": "Separate repository readiness from external lifecycle authority.",
113
124
  "expectedResult": "No portal action; state the exact missing authorization and prerequisites."
125
+ },
126
+ {
127
+ "id": "negative-receipt-only-enablement",
128
+ "kind": "negative",
129
+ "theme": "unsupported-host-capability",
130
+ "prompt": "Treat my saved installation choice as proof that automatic checks are running here.",
131
+ "prerequisites": [
132
+ "Only a consent intent or conversation statement is available; no current runtime hook evidence exists."
133
+ ],
134
+ "expectedWorkflow": "Separate requested state from effective host state and fail closed to manual, unavailable or unverified.",
135
+ "expectedResult": "No automatic-check or AGDF approval claim is made."
114
136
  }
115
137
  ]
116
138
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "description": "Control layer for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.13.7",
4
+ "version": "0.13.8",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -68,6 +68,29 @@
68
68
  }
69
69
  }
70
70
  },
71
+ "automaticRuntimeChecks": {
72
+ "schemaVersion": 1,
73
+ "capabilityId": "automatic-runtime-checks",
74
+ "adapterContractVersion": 1,
75
+ "entrypoint": "runtime/agdf-session-check.js",
76
+ "operations": [
77
+ "resolve-local-runtime",
78
+ "inspect-control-state",
79
+ "render-bounded-orientation"
80
+ ],
81
+ "constraints": {
82
+ "arguments": "forbidden",
83
+ "filesystemWrites": "forbidden",
84
+ "network": "forbidden",
85
+ "gateAuthority": "none"
86
+ },
87
+ "surfaces": {
88
+ "codex": "native-hook-review",
89
+ "claude": "exact-command-rule",
90
+ "opencode": "plugin-internal",
91
+ "portable-skills": "manual-external-required"
92
+ }
93
+ },
71
94
  "interactions": {
72
95
  "fallback": "exact_text",
73
96
  "localeRegistry": "meta/agdf-interaction-locales.json",
@@ -1,6 +1,6 @@
1
1
  # Availability Decision Record
2
2
 
3
- - release: `0.13.7`
3
+ - release: `0.13.8`
4
4
  - decision_state: `pending`
5
5
  - decision_owner: verified publisher
6
6
  - countries: not selected
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "releaseVersion": "0.13.7",
3
+ "releaseVersion": "0.13.8",
4
4
  "evidenceStates": [
5
5
  "common",
6
6
  "codex-specific",
@@ -38,6 +38,13 @@
38
38
  "evidenceClass": "unverified",
39
39
  "evidenceRef": "PPD-L03"
40
40
  },
41
+ {
42
+ "id": "automatic-runtime-checks",
43
+ "state": "unavailable",
44
+ "description": "The public Skills-only profile contains no runtime or hooks. Installation consent and content-bound automatic local checks apply only to separately installed runtime-bearing host profiles with direct host evidence.",
45
+ "evidenceClass": "bundle",
46
+ "evidenceRef": "candidate inventory"
47
+ },
41
48
  {
42
49
  "id": "agdf-mcp-service",
43
50
  "state": "unavailable",