@sabaiway/agent-workflow-kit 14.15.1 → 14.17.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/CHANGELOG.md CHANGED
@@ -4,6 +4,48 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 14.17.0 — the Recommendations screen offers the Jev walk while `TYPESAFE_API_KEY` is not set, and the walk starts with the key (AD-164 revised)
8
+
9
+ **While `TYPESAFE_API_KEY` is not in the environment the agent's commands run in, the Recommendations screen now
10
+ carries one optional item, `jev-connect`.** Its apply runs the read-only `/agent-workflow-kit jev` guide. Its
11
+ `recipe:` line is the decline: a preview of the ack writer that prints its `--apply` form; applied, it records
12
+ `jevConnectAck` in `docs/ai/acks.json`, and the item no longer shows for that project. With the key in the agent's
13
+ environment, no project shows it, and the key's value appears in no item, skip line or `--json` field.
14
+
15
+ - **The key comes first.** The walk now runs the key, the vendor skill, the first request. When `SHELL` is bash or
16
+ zsh, STEP 1 prints one line you run in a terminal of your own, outside the agent: it reads the key with no echo and
17
+ appends `export TYPESAFE_API_KEY=…` to `~/.bashrc` or `~/.zshrc`, so the key never passes through the agent or its
18
+ transcript. Any other shell gets a sentence to set it in an editor. Then restart the agent from a new terminal; if
19
+ the mark still reads `not set`, the mark's own text says to export the key in the file the agent's launcher reads,
20
+ then restart. `--json` gains `key.profile`.
21
+ - **The first request is one `curl` line.** STEP 3 prints the vendor's smallest documented request as a `curl`
22
+ command that reads the key from the environment, with its check (HTTP 200 and a department choice with a
23
+ confidence), then the three-ticket prompt. The mode doc tells the agent to run it only on your explicit yes in the
24
+ chat, since it sends the sample text to api.typesafe.ai, and never with a flag that prints request headers.
25
+ - **The guide itself is unchanged in kind:** it writes nothing, opens no connection and never prints the key's value.
26
+
27
+ ## 14.16.0 — `/agent-workflow-kit jev` walks you to a first Jev request: what it is, what it is not, three steps and three prompts where it pays (AD-164)
28
+
29
+ **A new read-only command, `/agent-workflow-kit jev`, recommends Jev (TypeSafe), a decision model that returns a typed
30
+ answer with probabilities and a confidence.** It says what Jev is, why it pays in this workflow, and what it is not,
31
+ quoting the vendor's own sentence that it is not a drop-in replacement for the LLM behind Claude Code, Cursor, opencode
32
+ or Copilot, then the jagged edges of jev-1.13, the confidence caveat and the retention terms as the vendor states them,
33
+ and its sources, each with the date it was read.
34
+
35
+ - **Three steps to a first request.** The vendor skill: both install forms, Claude Code's and the other agents', in a
36
+ fixed order, and a mark: `found` names each of five skill paths that holds a `typesafe-ai/SKILL.md`, `not seen`
37
+ says a plugin install is not visible to a file check and names the checks that do see it. The key: where to get it,
38
+ `TYPESAFE_API_KEY` exported before the agent starts, never pasted into the chat, and a `set` / `not set` mark. The
39
+ first use: a prompt routing three tickets, then the vendor's smallest documented request and response with the
40
+ field and error meanings, quoted.
41
+ - **Three prompts where it pays here:** the first real error in a red gate log, the decided-register entry a council
42
+ finding repeats, a paragraph that restates a named rule. Each tells the agent to keep every request within the vendor
43
+ limits (255 options, 64k tokens, 32k for the state plus the longest question), and each answer is a hint the agent
44
+ checks, never a gate; every candidate text goes to the vendor.
45
+ - **Safe to run anywhere.** The guide writes nothing, opens no connection and never prints the key's value; `--json`
46
+ gives the same content as an envelope. The command appears in the command list, the skill description and the
47
+ README's Use table.
48
+
7
49
  ## 14.15.1 — a fenced empty read-only file no rule calls a mask stops the probe, so a concurrent sandboxed command no longer turns its masks into real paths (AD-163)
8
50
 
9
51
  **`/agent-workflow-kit sandbox-masks` now withholds its verdict on a possible leftover.** While one sandboxed
package/README.md CHANGED
@@ -235,6 +235,7 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
235
235
  | `/agent-workflow-kit status` | any time | **read-only** single view of **versions + deployment + settings + bridges**: which members (kit / memory / engine / the two bridges) are installed and at what version (with an honest "installed on this machine" note when one is behind) and — in a project — what's deployed (`docs/ai`, the version stamps, and the **visibility**: visible / hidden / unclear), and the **feature-spec adoption state** (`not adopted` / `adopting (N draft)` / `adopted (N live, M draft)` / `could not be read`, plus `declined` when recorded), plus your settings (orchestration recipes, attribution, velocity) and the bridges' readiness. The two version axes (package number vs deployment-structure head) stay decoupled. Never writes, never commits, never runs a subscription CLI. |
236
236
  | `/agent-workflow-kit now` | any time | **read-only** answer to where work stands in four blocks: **NOW** names every plan in flight, its phase, current and next step, and the tree evidence; **STEPS** gives every ledger row its evidence-derived status; **QUEUE** folds named rows under their full heading paths and calls position priority only in the judged backlog; **CAMPAIGN** shows the source-size practice figures and config state. The plan's own text never sets a status; a contradicted claim prints beside it. A block that cannot be derived is WITHHELD with its cause; NOW has two halves, plans and tree, each independently a value or WITHHELD, and NOW itself is WITHHELD only when both are. Never writes, never commits, never runs a subscription CLI. |
237
237
  | `/agent-workflow-kit tier` | any time | **read-only** guide to the epic, story and task tier: what each level is, and the next step of the walk, with the command that runs it wherever a tool does. Never writes, never commits, never runs a subscription CLI. |
238
+ | `/agent-workflow-kit jev` | any time | **read-only** guide to Jev (TypeSafe), a decision model: what it is, why it pays here, what it is not, the three steps to a first request and three prompts where it pays. Opens no connection and never prints the key. |
238
239
  | `/agent-workflow-kit recipes` | any time | **read-only** orchestration advisor: presents five named recipes for composing the carriers of a step — the bridges and the full-tool executor subagent — into plan → execute → review — **Solo / Reviewed / Council / Delegated / Subagent** — plans + recommends one for your environment (degrading with a stated reason when a backend isn't ready, or when the executor vehicle is missing/unusable), and offers the choice. The activity/slot registry (six activities) is rendered by `procedures` and by `set-recipe --help`. The orchestrator runs it via the bridge skills or the executor vehicle and **always commits**; the kit never executes a recipe, never runs a subscription CLI, never commits. |
239
240
  | `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution` / `routine` / `feedback-triage` / `epic` / `task`) read **live** from the engine, plus the **resolved recipe per slot** from your `docs/ai/orchestration.json` (agent-writable via `set-recipe`, or hand-edited) + carrier readiness (`plan-authoring`: author, fold, review; default Reviewed when a backend is ready, Council on request; slot-aware incl. Delegated and Subagent) — and, for every dispatched backend, the **full driving contract at the point of use** (exact copy-pasteable invocation, grounding levers like agy's `--facts`/`--decided`, the round-2 `--continue` delta, guarded passthrough), verbatim from the bridge manifests (drift-guarded; each wrapper's `--help` prints the same) — except `feedback-triage`, whose record-bound block carries the check with `--excerpts`, the resolved member lines (ready bridge commands, the ready lens brief, or explicit skipped members), and either the record round-table command for a bridge obligation or the no-receipt fact otherwise: the record is the artifact. `--override <slot>=<value>` adjusts one slot per run. Composes with `recipes`; never writes, never commits, never runs a subscription CLI. |
240
241
  | `/agent-workflow-kit set-recipe` | any time | **config writer** for `docs/ai/orchestration.json`: tell the agent your preference in plain language and it maps it to explicit `--set <activity>.<slot>=<value>` / `--unset` ops; the kit validates, **previews by default**, and writes only on `--write` (deployment-gated, atomic, symlink/TOCTOU-safe), resolving the effective recipe vs live readiness. Writes **only** that file — **never runs a backend or a subagent, never commits**; hand-editing stays fully supported. |
@@ -245,7 +246,7 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
245
246
  | `/agent-workflow-kit core-evidence` | any time | **the ONE loop-evidence writer** (strip-the-kit) — every core evidence record lands in a single append-only JSONL store inside the git dir (never committable; versioned schema, latest-per-key supersession, byte-identical duplicates refused, malformed lines fail every reader closed). `red-proof "<file>#<pattern>"` declares an observed-red **BEFORE a bugfix** (N/N red runs + content custody + base + the pre-fix fingerprint; green/mixed/timeout are DISTINGUISHED refusals — nothing written); `degrade --backend --reason` is the ONLY escape for an unavailable review backend (per-tree, never all backends); `summary` renders the whole loop state statelessly (gate result · per-backend verdicts · red-proofs · degrades) — no ledger, no rounds, nothing remembered. Honest residual: records are forgeable — self-discipline, not a security boundary. Never commits, never runs a subscription CLI. |
246
247
  | `/agent-workflow-kit coverage-check` | any time | **the final-run checker** (D3(c)+(d)) — **certifies coverage ONLY inside the `--final` run that owns the lcov** (ownership is exclusive by CONVENTION over the fixed path, not enforced — a concurrent writer to it is a stated residual, queued as LCOV-EXCLUSIVE-OWNERSHIP): an artifact on disk proves nothing about the tree it came from, so a standalone run prints its findings and states `attested=no` / `NO VERDICT` rather than a PASS (an lcov that predates an edit would otherwise certify a line the suite never executed). `attested=` claims a verdict was ISSUED, pass or fail — a run over uncovered lines still reads `attested=yes` and still exits 1, and a run whose coverage arm never executed (no lcov) reads `attested=no` even inside `--final`, because nothing was read and nothing is certified. The runner passes a nonce whose one-way commitment over `{nonce, fingerprint, base}` is the `final-start.attempt` it recorded; a context describing another tree, or matching no recorded attempt, is a REFUSAL, never a verdict. Findings are unchanged — reads the lcov the declared `unit-tests` gate produced at the FIXED git-dir path and fails on any uncovered CHANGED executable Node line (listed `file:line`; a changed file absent from the map is a file-level red; out-of-domain/unsupported files are LISTED — the claim narrowed honestly); VERIFIES every current-base red-proof declaration (bound test exists · custody hash unchanged · green N/N now · pre-fix fingerprint differs); prints `lcov-sha256=<hex|none>` of the exact bytes it consumed — the sha the `--final` receipt binds and re-hashes. An absent lcov is a LOUD `skipped-no-lcov`; a symlinked path is a refusal. `--check` is the gate exit code — declare it as the LAST gate (`run-gates --final` refuses otherwise). Read-only. |
247
248
  | `/agent-workflow-kit commit-guard` | any time | **the read-only pre-commit guard** (D10) — makes the commit capture the whole current working tree, so «verified» and «about to be committed» are the same bytes (the receipt itself has a stated residual — see the mode doc). FIRST it refuses an **INDEX that lags the verified working tree** (the gates and the fingerprint describe the WORKING tree while `git commit` takes the INDEX alone, and the fingerprint cannot tell them apart — so a lagging index used to ship a strict subset of what was verified): unstaged tracked paths or reviewable untracked-not-ignored paths, named up to a bounded cap with the remainder stated, a dirty tracked **submodule** named separately with its own recovery, and fail-closed on an undecidable probe. This deliberately blocks a partial commit. Then it binds the LATEST completed `run-gates --final` receipt to the EXACT current tree: refuses on a missing/red/stale receipt, fingerprint drift under the run, a dangling later attempt, declaration content drift, evidence-hash or lcov drift, or unsatisfied review obligations (the same review-state decision, recomputed over a sanitized env — forged out-of-repo stores never satisfy). Re-runs NO gate or test. Wire it into `.git/hooks/pre-commit` (the installer writes the RESOLVED invocation). `git commit --no-verify` stays the stated residual. |
248
- | `/agent-workflow-kit recommendations` | any time (every `upgrade` ends with it) | **read-only deployment advisor** (AD-044) — computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, OS sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe, a feature-spec layer never adopted) and renders **verdict-first**: one composed verdict line (does anything need attention?), then each item as **{severity · what · one-line benefit · an optional `recipe:` line (the sandbox-lane live recipe, the worktrees-dir hand-apply-first grant advice, the agents hidden-mode reconcile follow-up, or the spec-adoption decline preview) · the exact consent-gated apply one-liner}**. The agent PRESENTS the section in the user's conversational language — every fact and count, nothing added or dropped; commands, paths, hosts and rule strings byte-exact; raw tool block on request — and runs EXACTLY the rendered one-liners only on your yes, surfacing each item's posture note first. Renders **present-even-when-empty** (`no recommendations — flow optimal.`); a failed probe degrades to a stated skip line. Registry strings are fact-true frozen one-line data (posture/risk notes live in the mode doc at the consent moment); the kit never seeds `sandbox.network.allowedDomains` / `filesystem.allowWrite` (**HAND-APPLY** territory), and the sandbox-lane item's convergence is a neutral fingerprint acknowledgement recorded by a consent-gated ack writer into `docs/ai/acks.json` — never a security key (the recipe is documented per bridge in `capability.json` `networkHosts` + `writableDirs`). `--cwd` is required (the target project is explicit); never writes, never commits, never runs a subscription CLI. |
249
+ | `/agent-workflow-kit recommendations` | any time (every `upgrade` ends with it) | **read-only deployment advisor** (AD-044) — computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, OS sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe, a feature-spec layer never adopted) and renders **verdict-first**: one composed verdict line (does anything need attention?), then each item as **{severity · what · one-line benefit · an optional `recipe:` line (the sandbox-lane live recipe, the worktrees-dir hand-apply-first grant advice, the agents hidden-mode reconcile follow-up, the spec-adoption decline preview, or another offer's decline preview) · the exact consent-gated apply one-liner}**. The agent PRESENTS the section in the user's conversational language — every fact and count, nothing added or dropped; commands, paths, hosts and rule strings byte-exact; raw tool block on request — and runs EXACTLY the rendered one-liners only on your yes, surfacing each item's posture note first. Renders **present-even-when-empty** (`no recommendations — flow optimal.`); a failed probe degrades to a stated skip line. Registry strings are fact-true frozen one-line data (posture/risk notes live in the mode doc at the consent moment); the kit never seeds `sandbox.network.allowedDomains` / `filesystem.allowWrite` (**HAND-APPLY** territory), and the sandbox-lane item's convergence is a neutral fingerprint acknowledgement recorded by a consent-gated ack writer into `docs/ai/acks.json` — never a security key (the recipe is documented per bridge in `capability.json` `networkHosts` + `writableDirs`). `--cwd` is required (the target project is explicit); never writes, never commits, never runs a subscription CLI. |
249
250
  | `/agent-workflow-kit doc-parity` | any time | **read-only doc-parity lint** (AD-049) — kills the doc-drift class where a mode-contract doc silently lags a code constant (a `--check` doc still reading `300` after the diff cap moved to `400`): a **closed, exported registry** binds each live constant (review caps, schema versions, the ledger's own class/scope vocabulary, and the autonomy-doctor EXIT/status/trusted-dir contract) to the exact token its `references/modes/*.md` contract must carry, and asserts the CURRENT value renders into every bound file — a drifted doc, an unreadable file, or an absent token **fails closed**. The values are sourced from the live imports (never re-typed), so the lint can't itself go stale; adding a binding is adding a checked entry (closed-world, edit-safe). `--check` is the gate exit code a kit maintainer runs: the lint checks the kit's own package. Never writes, never commits, never runs a subscription CLI. |
250
251
  | `/agent-workflow-kit dispatch` | any time | **the delegation engine** — makes "how much does delegating a sub-task actually buy?" a measured number instead of a feeling. `check <file>` validates a sub-task brief's contract block and exits 0/1 naming the first violated field — **form only**: whether the task is genuinely bounded, its design decided and its acceptance adequate stays your judgment, and a well-formed absurdity passes here by construction. `advise --step-class <c>` answers the question that comes BEFORE that one — which vehicle should carry this kind of sub-task, whether it is even present on this machine, and what the ledger has already recorded for threads of that class (finished, failed, closed without a fold, and still open — counted separately) — and it decides nothing: it refuses no dispatch, gates no verb, and a choice that diverges from the advice is noted rather than blocked. It reads the filesystem only: nothing is launched to find out what is installed, an absent ledger prints "no recorded history", an unreadable one prints the store's own words, and either way the advice still prints. The same block appears as a footer under a form-valid `check` — never under a refusal, so it can never hide one. `register` pre-registers an acceptance wave (step classes, pairing key, minimum observations per class, the mean and first-pass thresholds) so the bar can never be chosen after the results it judges — immutable per wave. `observe` records ONE hand-written observation (`solo-construction`, the baseline whose ratio is 1 by construction — except over a scope measuring zero bytes, which has no ratio at all and is recorded ineligible by name — or `self-reported`) — delegated numbers are never hand-written, they are derived. The writer verbs are where that derivation happens: `open` puts a delegated thread on the record with every mint-time field copied from the brief's own header, refusing a deadline the wrapper's cap plus its kill grace would not fit inside, and recording whether the tree it started from was clean against the thread's base — HEAD by default, or the tree `--checkpoint <oid>` names, so the second task of a story is measured over the first one's uncommitted work instead of opening dirty (a dirty one makes the result honestly unmeasurable rather than quietly counted), while `--task <brief>` also records which task brief the thread carries out and the files that brief lists, refusing, since the last commit, a task thread whose files overlap by path prefix those of an open task thread or of a folded thread of another brief (`files-overlap`), and a mix of the two kinds — an untasked open beside an open task thread or, for a `code` open of backend `codex`, after a task fold, and a task open beside an open untasked thread (`mixed-open`), refusing at open a Files path the snapshot scope can never hold (`task-files-scope`), and measuring a task thread over its files alone, so `return` and `fold` refuse a changed path that no open or folded task thread on the same base claims (`out-of-files`); `await` waits for that one dispatch to answer and writes nothing — only the finished receipt satisfies it, a run still holding the nonce means keep waiting, and a wait that runs out says so with its own exit code, names whether the deadline or your own timeout ended it, and authorizes nothing: a wait that ended without an answer is a question for you, never permission to dispatch again; `return` absorbs the receipt the wrapper minted — only a finished one, checked against the contract it actually ran, its deadline and its own report, and refused outright when the tree hides changes from git or moves while the return is being computed — and derives the bytes from git rather than from anyone's claim; `fold` is the acceptance, and it refuses if the tree moved since the return — precisely, it re-confirms **equality of the visible canonical payload**, which is a change detector rather than a cryptographic identity of the tree: under the default head base that payload's untracked section is unframed and carries no file mode, so a content or symlink target that imitates the marker opening the next entry can alias two trees, and making an untracked file executable moves nothing (both named as residuals in the mode doc, with the fix queued); under a checkpoint base it is one indexed diff that carries modes. A change set carrying a binary, a non-regular path, a submodule, or a symlink whose target is not valid UTF-8 is **refused** at `return` and `fold` — CONSERVATIVELY, rather than promise what the default head payload may not be able to follow — and the same refusals hold for a checkpoint thread. `degrade` closes a thread that never earned a fold, on the record and with its reason. `aggregate` prints one wave: the registered thresholds, every observation as context, and per step class the finished threads — a folded success with git-provable bytes contributes its ratio, one whose bytes are unprovable is excluded from the mean but still counts in the first-pass rate, and a failed thread, a degrade-closed one, or one folded after failing acceptance each count as a real zero. Below the registered minimum nothing is computed (insufficient); at or above it is computed and labeled PILOT evidence. It REFUSES rather than guessing: no pre-registration, an unfinished thread in scope, a recorded refusal-to-delegate that never opened a thread, or an ambiguous wave each stop the computation by name. `handoff-return --slug <s>` closes the worktree loop after `land --prepare`: it re-attests that main still holds exactly the prepared tree under the same HEAD (both recorded in the handoff at prepare time), prints the satellite handoff's user-owned content byte for byte with its boundaries, byte lengths and the main-owned destinations each part folds into, prints the handoff digest and both OIDs as its proof, states the after-the-fold order (a fold landed after the gates leaves them stale), and records ONE self-reported worktree-stream observation only when the whole prepared change set is measurable — a deletion, a rename, a symlink, a submodule or a mode-only change ends with a named NOT RECORDED instead, never a partial number. Appends only to its own ledger inside the git dir (never committable); it also writes `handoff-return`'s `write-tree` tree object and, for a checkpoint measurement, the leaf's OWN temporary index file and the blobs its forced adds store — never a ref, never the real index; never commits, never runs a subscription CLI. |
251
252
  | `/agent-workflow-kit worktrees` | any time | **parallel feature worktrees** — run several features in DIFFERENT agent sessions on one repo, zero interference on working-tree files (the ONE exception is the dependency cache, below): `provision <slug> --plan <file>` creates a sibling git worktree on branch `aw/<slug>` and populates it (registry-derived footprint copy-if-missing — a tracked file is never overwritten; EXACTLY ONE seeded feature plan; the `handoff-<slug>.md` record from minute zero; `node_modules` symlinked where the link stays ignored — a shared MUTABLE dependency cache: writes through it hit MAIN's node_modules; for isolation run the printed isolated-install command (`--install` only PRINTS it; on `--resume` run the printed unlink-first recovery first — printed only for a link whose RAW TARGET is MAIN's `node_modules`, since a foreign or unreadable link is reported as such with no removal advised); absolute root-pinned gate commands rebased on untracked copies only, and only while their bytes equal the MAIN source or its rebased form — user-modified copies stay untouched); `list` is read-only (slug, branch, base, dirty, handoff); `prompt <slug>` is read-only too and re-prints the satellite's cold-start prompt — the same text `provision` ends its report with: where the worktree is, its ONE seeded plan, the handoff as the one channel back, MAIN's orientation (shared series index, landing) and, under its own heading because it is probed on the satellite, that checkout's install posture — every value derived LIVE rather than replayed from the frozen provision record, a recorded value that no longer matches NAMED as a divergence (with the cause its source makes likely) instead of printed as the runnable one, every offered command marked with WHO runs it (`MAIN $ …` for the landing, `HERE $ …` for this checkout's own install, a posture with nothing to run staying prose), and a control character in any rendered value a typed STOP rather than a forged prompt line; `land <slug> --prepare` locks the common git dir, fail-closes on divergence or incomplete satellite state, transfers the complete accepted satellite diff onto a CLEAN main, runs sync plus the declared gates, and reports HEAD/TRANSFER/PREPARED OIDs — the commit ALWAYS stays a dialogue ask; `cleanup <slug>` takes the same lock and removes a LANDED worktree only after live landed-verification against main HEAD, while `--abandon` is the ONE destructive arm (destroys unlanded work; **no preview step** on any writer). The parent dir is the `docs/ai/worktrees.json` `parentDir` setting (default: the repo's sibling parent); an unwritable parent degrades to printed maintainer-pasted commands, and the one-time host consent that makes it promptless surfaces via `recommendations`. Never commits, never pushes, never runs a subscription CLI. |
package/SKILL.md CHANGED
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: agent-workflow-kit
3
- description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow". New to the epic, story and task tier? Run `/agent-workflow-kit tier`.
3
+ description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow". New to the epic, story and task tier? Run `/agent-workflow-kit tier`. A typed decision with a confidence from Jev? Run `/agent-workflow-kit jev`.
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '14.15.1'
6
+ version: '14.17.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
@@ -119,6 +119,10 @@ read-only — read `${CLAUDE_SKILL_DIR}/references/modes/now.md` before acting.
119
119
 
120
120
  read-only — read `${CLAUDE_SKILL_DIR}/references/modes/tier.md` before acting.
121
121
 
122
+ ### Mode: jev
123
+
124
+ read-only — read `${CLAUDE_SKILL_DIR}/references/modes/jev.md` before acting.
125
+
122
126
  ### Mode: recommendations
123
127
 
124
128
  read-only — read `${CLAUDE_SKILL_DIR}/references/modes/recommendations.md` before acting.
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "14.15.1",
6
+ "version": "14.17.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "14.15.1",
3
+ "version": "14.17.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -0,0 +1,23 @@
1
+ ### Mode: jev
2
+
3
+ <!-- opt-in-capability: jev-connect -->
4
+
5
+ Read-only. The Jev guide: what Jev (TypeSafe) is, why it pays in this workflow, what it is not, the three steps to a first request and three prompts where it pays. The guide writes no file, opens no connection, never prints the key's value and never commits.
6
+
7
+ Run `node ${CLAUDE_SKILL_DIR}/tools/jev-guide.mjs --dir <project> --json`.
8
+
9
+ Render the returned envelope compactly in the user's conversational language. Never paste the JSON. Keep every path and every command verbatim, each command on its own line so it runs as printed; translate only the prose around them. Keep every vendor-quoted text verbatim and in quotes, never translated or reflowed: the not-a-replacement sentence, the curl line, the response, the three field meanings and the four error meanings.
10
+
11
+ Walk the steps with the user in order, one at a time; move on when the step's check passes or the user skips it. STEP 1: the user runs the key line in a terminal of their own, never the agent. STEP 2: the user runs the install lines — they change the agent's own configuration outside the project. STEP 3: run the curl line only on the user's explicit yes in the chat — it is a network call that sends the sample text to api.typesafe.ai — and never with `-v`, `--trace` or any flag that prints request headers; under an OS sandbox the host must be reachable, and a blocked host is named by the sandbox: the user allows it or runs the line in their own terminal.
12
+
13
+ Keep this order: the fixed text (WHAT, WHY HERE, NOT, SOURCES); then the three steps — the key with its line or its editor sentence and its mark, the vendor skill with its install lines and its mark, the first request with its curl line and its check; then the three prompts where it pays.
14
+
15
+ Exit codes:
16
+
17
+ | Code | Meaning |
18
+ |------|---------|
19
+ | 0 | Rendered, or `--help` / `-h` as the whole invocation. |
20
+ | 1 | Nothing rendered: a stat of the `--dir` does not report a directory; the cause is printed on stderr. |
21
+ | 2 | Usage: an unknown argument, a `--dir` without a value, or `--help` / `-h` combined with anything. |
22
+
23
+ **Invariants:** the guide is read-only and opens no connection · the agent runs STEP 3's curl line only on the user's explicit yes · the key's value never printed · compact user-language render with paths, commands and vendor quotes verbatim · process.exitCode, never process.exit().
@@ -4,7 +4,7 @@
4
4
 
5
5
  Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md
6
6
 
7
- The **read-only deployment advisor** — the deterministic section every `upgrade` run ends with, also invocable on its own. It computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, sandbox unavailable, gates undeclared, a declared gate matrix that verifies nothing, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe, a configured `subagent` carrier whose executor vehicle cannot carry it, a difference from the reference profile the project has not declined) and renders **verdict-first**: one composed verdict line, then each item as **{severity · what is sub-optimal · the benefit in ONE plain line · an optional `recipe:` line (the `sandbox-lane` live recipe — egress hosts + resolved writable dirs — the `worktrees-dir` hand-apply-first grant advice, or the `agents` / `executor-vehicle` hidden-mode reconcile follow-up) · the exact consent-gated apply one-liner}**. The tool computes deterministic English DATA; **you PRESENT the section in the user's conversational language** — every fact, count and item from the tool, nothing added or dropped; commands, paths, hosts and rule strings stay **byte-exact**; show the raw tool block on request (the AD-032 report-contract lane — the tool cannot know the dialogue language, so the language rendering is your presentation layer).
7
+ The **read-only deployment advisor** — the deterministic section every `upgrade` run ends with, also invocable on its own. It computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, sandbox unavailable, gates undeclared, a declared gate matrix that verifies nothing, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe, a configured `subagent` carrier whose executor vehicle cannot carry it, a difference from the reference profile the project has not declined, Jev not connected on this host) and renders **verdict-first**: one composed verdict line, then each item as **{severity · what is sub-optimal · the benefit in ONE plain line · an optional `recipe:` line (the `sandbox-lane` live recipe — egress hosts + resolved writable dirs — the `worktrees-dir` hand-apply-first grant advice, or the `agents` / `executor-vehicle` hidden-mode reconcile follow-up) · the exact consent-gated apply one-liner}**. The tool computes deterministic English DATA; **you PRESENT the section in the user's conversational language** — every fact, count and item from the tool, nothing added or dropped; commands, paths, hosts and rule strings stay **byte-exact**; show the raw tool block on request (the AD-032 report-contract lane — the tool cannot know the dialogue language, so the language rendering is your presentation layer).
8
8
 
9
9
  **Live host/session facts are tool-composed only.** Every fact this section states about the current
10
10
  host or session — prompts fired, sandbox scope, whether a bypass was needed, network reachability,
@@ -38,6 +38,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd <project-root> [--
38
38
  - ADDITIONAL `gates-inert` arms (the third outcomes) — two further arms, and they differ in whether anything is BROKEN. **`producer-unrecognized`** — a checker with no producer anywhere in the declaration, on a tracked tree the changed-line coverage domain cannot reach (`.ts`/`.tsx`/`.jsx`/`.mts`/`.cts` strictly outnumber `.mjs`/`.cjs`/`.js`): the dead pair is real, so this arm is **HAND-APPLY** and the two remedies are marking the real producer with `"lcovProducer": true` or dropping the checker. Never a `node --test` prescription over a project that has no such suite, never the fill preview, and never an acknowledgement — a dead pair is broken, not narrow, and removing a producer after an acknowledgement lands right back in this arm. **`coverage-domain-narrow`** — the producer/checker pair IS live and the tree is still dominated by what the domain excludes: nothing is broken, and the honest sentence is that certification covers the assessable minority. Its apply is the consent-gated **ack writer** preview (a NEUTRAL fingerprint into `docs/ai/acks.json` as `coverageDomainAck`, never a security key); after the SAME confirmation you run the `--apply` it prints. The fingerprint binds the FACT — the verdict plus the unsupported extensions present, never the file counts — so an acknowledged project stays quiet as it grows and re-fires when a new unsupported language arrives or the verdict flips. The census reads the TRACKED tree with a read-only `git ls-files`; a tree it cannot read (a non-git deployment) becomes a stated skip, so optimality is withheld rather than assumed. Risk profile: no enforcement change of any kind — one acknowledgement recorded in a family-owned file, and one hand edit that stays the maintainer's.
39
39
  - `spec-adoption` — the feature-spec layer's ADOPTION STATE, judged from `docs/ai/specs/` alone through the same census `spec-check --all` runs, so a store the checker would refuse to observe is never counted here either. Both arms are OFFERS (`optional`) — the layer is opt-in, and `attention` stays reserved for a configured declaration that is broken. **`not-adopted`** (no store): every plan then cites zero governing specs by default and nothing says adoption never started; its apply is the spec-layer ensure one-liner (`ensure-configs --reconcile --only specs`, the same seed `upgrade` runs — it writes the reader/checker pairs and the store root, create-only, and skips with a stated reason where no Node evidence exists), and its `recipe:` line carries a NAMED **HAND-APPLY alternative** — the DECLINE preview (`ack-write --lane spec-adoption`, a dry-run that prints the exact `--apply`), which records `specAdoptionAck` in the family-owned `docs/ai/acks.json`. **The two are exclusive, and the order is part of the contract:** ask which the maintainer wants BEFORE the confirmation; on "seed" run the apply; on "decline" run NOTHING — hand over the preview line and let them run it and its printed `--apply`; never run the seed after a decline was chosen, and never run the decline preview for them. **`adopting`** (a store with no live contract): an optional item naming the draft count; its apply is that same decline preview (a dry-run; after the SAME confirmation you run the `--apply` it prints), and the honest remedy is authoring a contract from the skill's `SPEC_TEMPLATE.md`. A recorded decline silences BOTH arms and shows on `status` as ` — declined`; one live contract makes the decline moot. An unreadable store is a stated skip, never `flow optimal`. Risk profile: the seed writes only create-only files under `scripts/` and `docs/ai/specs/`; the decline writes one key into the ack store; nothing here authors a spec or blocks a plan.
40
40
  - `profile-gap` — each item's apply is a PREVIEW that writes nothing, and consent takes two steps: the confirmed pick runs the preview and you relay every line it prints (the environment-resolved slot values, each checker `entry:` line with its trust-chain disclosure, a Communication region the insert plans in the same run); the same line with ` --apply` appended runs only on a SECOND yes over those lines, never carried by the first. Items whose apply lines are byte-equal are one writer and take one answer: the tier preview's `--apply` writes the absent slots, the store seed and the queue seed together; the checker verb writes only its own entries; the insert writes every region it plans, all or nothing, so a `communication-absent` skip beside a declined `story-sessions-section` gets its own ask after the insert's full preview. A no records nothing and the item stays on the screen. A DECLINE is asked apart from later, before anything runs, and runs `node ${CLAUDE_SKILL_DIR}/tools/tier-preview.mjs --decline --cwd <project-root>` only when the user refuses EVERY item the tier preview then reports offered: it records each of them at the shipped lineage, and a declined item leaves the screen until a lineage step changes the profile. An undecidable entry is a stated skip naming its reason, the remedy by reason: a prior → the upgrade's `lens` reconcile; an absent region → the insert; a customized region → a hand edit only (the lens preserves it), so that skip stands and withholds `flow optimal`. Risk profile: the tier preview's `--apply` rewrites `docs/ai/orchestration.json` in canonical form with the `_README` note and creates `docs/ai/epics/.gitkeep` and `docs/plans/queue.md` create-only; the insert adds regions to `docs/ai/agent_rules.md`; the checker verb adds entries to the PRIVILEGED `docs/ai/gates.json`; the decline writes `docs/ai/profile-declines.json`; nothing here commits.
41
+ - `jev-connect` — the apply runs the read-only Jev guide and writes nothing; then walk its three steps by the jev mode doc. On bash or zsh the walk's key line appends the key in plain text to the user's startup file (readable by any process running as that user, and by other local accounts when the file is world-readable in a traversable home, as a new ~/.zshrc in a default macOS home is) and is run by the user, never the agent; the first request sends the sample text to api.typesafe.ai only on the user's yes; the vendor keeps data under its processing agreement and offers zero retention only to enterprise accounts. The item reads the environment the agent's commands run in: a host setting that filters it shows the item while the key is set in the user's shell. The decline is the HAND-APPLY alternative on the recipe line, asked apart BEFORE the confirmation (the `spec-adoption` order): on "connect" run the apply, on "decline" run nothing and hand over the line, never the apply after a decline was chosen; the decline is recorded per project as `jevConnectAck` in `docs/ai/acks.json`. Risk profile: a plain-text key in the user's startup file, written by the user; one network call on the user's yes.
41
42
  - `adr-store-migration` — other items write project files too; what is unique here is that the crossing **overwrites and deletes files the project already has**: it replaces the deployed enforcement scripts in `scripts/` (the directional subset — only basenames the project already has; a locally-edited copy is snapshotted first, never silently clobbered) and, where a retired archive file exists, DELETES it once conservation has been proven. That is why it is **HAND-APPLY** and why the command shown in the apply slot is a **`--dry-run`** — it writes nothing and prints the whole plan. `--apply` is a SEPARATE step, run only after that plan has been shown and **fresh consent** obtained for it; the consent flow executes only the apply slot, so an item that needs consent AFTER its preview cannot use that lane at all. Every write is idempotent and the run is re-runnable to completion after any interruption, so a re-run repairs rather than double-applies. It never commits. Risk profile: overwrite + delete of existing project files, gated on a preview you have actually read.
42
43
 
43
44
  **Sandbox lanes (what to DO with the `sandbox-lane` recipe, per host class):**
@@ -14,6 +14,7 @@ export const ACKS_WORKTREES_DIR_KEY = 'worktreesDirAck';
14
14
  export const ACKS_COVERAGE_DOMAIN_KEY = 'coverageDomainAck';
15
15
  export const ACKS_SOURCE_SIZE_COPY_KEY = 'sourceSizeCopyAck';
16
16
  export const ACKS_SPEC_ADOPTION_KEY = 'specAdoptionAck';
17
+ export const ACKS_JEV_CONNECT_KEY = 'jevConnectAck';
17
18
 
18
19
  // The CLOSED-WORLD ack-lane registry: the lane name an advisor item renders on the writer's command line ->
19
20
  // the store key that writer sets. A lane the registry does not name is a usage refusal at the writer.
@@ -23,6 +24,7 @@ export const ACK_LANES = Object.freeze({
23
24
  'coverage-domain': ACKS_COVERAGE_DOMAIN_KEY,
24
25
  'source-size-copy': ACKS_SOURCE_SIZE_COPY_KEY,
25
26
  'spec-adoption': ACKS_SPEC_ADOPTION_KEY,
27
+ 'jev-connect': ACKS_JEV_CONNECT_KEY,
26
28
  });
27
29
 
28
30
  export const FINGERPRINT_LENGTH = 16;
@@ -98,6 +98,13 @@ const CATALOG = [
98
98
  kind: READ_ONLY,
99
99
  oneLine: 'Explain the epic, story and task tier in plain words and name the next step of the walk, with the command that runs it wherever a tool does: the tier guide reads the disk alone.',
100
100
  },
101
+ {
102
+ key: 'jev',
103
+ invocation: invocationOf('jev'),
104
+ group: 'Inspect',
105
+ kind: READ_ONLY,
106
+ oneLine: 'Guide to Jev (TypeSafe), a decision model: what it is, why it pays here, the steps to a first request and three prompts where it pays; the guide opens no connection.',
107
+ },
101
108
  {
102
109
  key: 'backends',
103
110
  invocation: invocationOf('backends'),
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+ // spec:jev-guide — docs/ai/specs/kit/jev-guide/index.md
3
+ import { statSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
5
+ import { basename, join, resolve } from 'node:path';
6
+ import { fail } from '../references/scripts/markdown-blocks.mjs';
7
+ import { isDirectRun } from './direct-run.mjs';
8
+
9
+ const SCHEMA = 1;
10
+ const KEY_VARIABLE = 'TYPESAFE_API_KEY';
11
+ const SKILL_FILE = join('typesafe-ai', 'SKILL.md');
12
+ const HELP = `jev — read-only: what Jev (TypeSafe) is, why it pays here, and the steps to a first request.
13
+
14
+ Usage:
15
+ node jev-guide.mjs [--dir PROJECT] [--json]
16
+
17
+ --dir the project to read (default: the current directory).
18
+ --json the JSON envelope instead of the plain text.
19
+ --help answered only when it is the whole invocation.
20
+
21
+ Exit codes: 0 rendered; 1 nothing rendered (a --dir that is not a directory); 2 usage.
22
+
23
+ Reads only: the --dir, the home directory, the key variable's presence, the SHELL variable and five skill paths; no network.`;
24
+
25
+ export const JEV_TEXT = Object.freeze([
26
+ 'WHAT: Jev is a decision model: it takes a state and typed questions (choice, score, noul) and returns typed answers with probabilities and a confidence; it does not write text.',
27
+ 'WHY HERE: a typed decision with a confidence instead of prompt-and-parse, in the user\'s own code and in the agent\'s scratch scripts.',
28
+ 'Price and latency as the vendor states them: 0.042 dollars per million input tokens, output free; sub-second.',
29
+ 'NOT: "Jev is not a drop-in replacement for the LLM behind Claude Code, Cursor, opencode, Copilot" (the vendor).',
30
+ 'Jagged edge of jev-1.13: it reads literally.',
31
+ 'Jagged edge of jev-1.13: no counting or arithmetic.',
32
+ 'Jagged edge of jev-1.13: dates are read as text.',
33
+ 'Jagged edge of jev-1.13: a large irrelevant state distracts it.',
34
+ 'Jagged edge of jev-1.13: adversarial content can move the answer.',
35
+ 'Jagged edge of jev-1.13: indirection lowers accuracy.',
36
+ 'Jagged edge of jev-1.13: no structural invariants across questions.',
37
+ 'Jagged edge of jev-1.13: no generation.',
38
+ 'A confidence is not a correctness: start with conservative thresholds and test with your own data.',
39
+ 'Retention as the vendor states it: zero data retention for enterprise customers only; a data processing agreement covers retention; a commitment not to train on user data.',
40
+ 'SOURCES: docs.typesafe.ai for every Jev claim, read 2026-09-29.',
41
+ 'The skills CLI README (github.com/vercel-labs/skills) for the skill paths, read 2026-09-29.',
42
+ 'code.claude.com for claude plugin list, read 2026-09-29.',
43
+ ]);
44
+
45
+ const INSTALL = [
46
+ 'Claude Code:',
47
+ 'claude plugin marketplace add typesafe-ai/skills',
48
+ 'claude plugin install typesafe@typesafe-ai',
49
+ 'Other agents:',
50
+ 'npx skills add typesafe-ai/skills --skill typesafe-ai',
51
+ ];
52
+ const NOT_SEEN = [
53
+ 'skill: not seen at the five skill paths. A plugin install is not visible to a file check; check it by its owners:',
54
+ '/typesafe:typesafe-ai',
55
+ 'in a Claude Code session (the vendor); ask any other agent to use the TypeSafe skill (the vendor); or run Claude Code\'s own',
56
+ 'claude plugin list',
57
+ ];
58
+ const PROFILES = Object.freeze({ zsh: '~/.zshrc', bash: '~/.bashrc' });
59
+ const KEY_LINE = 'set +x; printf \'TYPESAFE_API_KEY: \' && read -rs k && echo && { echo; printf \'export TYPESAFE_API_KEY=%q\' "$k"; echo; } >> PROFILE && unset k';
60
+ const KEY_GET = 'Get a key at console.typesafe.ai and set it on every host the agent runs on.';
61
+ const KEY_RUN = 'Run this line yourself in a terminal of your own, outside the agent: it reads the key with no echo, so the key never passes through the agent or its transcript.';
62
+ const KEY_EDITOR = 'Set TYPESAFE_API_KEY to your key in your shell\'s startup file, in an editor and in that shell\'s own syntax, never through the chat or a project file.';
63
+ const KEY_RESTART = 'Then quit the agent, start it again from a new terminal, and run /agent-workflow-kit jev again: the key mark reads set.';
64
+ const KEY_NEVER = 'Never paste the key into the chat or into a project file.';
65
+ const keyNotSet = (profile) => `key: ${KEY_VARIABLE} not set. A host setting that filters the environment of the agent's commands also hides it. If it still reads not set after a restart and no such setting applies, the agent may not have been started from a shell that reads ${profile ?? 'that startup file'}: export the variable in the file the agent's launcher reads, then restart.`;
66
+ const CURL = 'set +x; curl -q -sS -w \' HTTP %{http_code}\' -X POST https://api.typesafe.ai/v1/systemone -H "Authorization: Bearer $TYPESAFE_API_KEY" -H "Content-Type: application/json" -d \'{"state":"Help! My payouts have been failing for 3 days.","model":"jev-latest","questions":{"department":{"type":"choice","instructions":"Which team should handle this?","criteria":{"billing":"Payments, invoicing, refunds","technical":"Bugs, outages, integrations","sales":"Pricing, upgrades, new accounts"}}}}\'';
67
+ const FIRST_USE = [
68
+ 'The vendor\'s smallest documented request, reading the key from the environment:',
69
+ CURL,
70
+ 'The check: HTTP 200 and a response whose answers.department carries a choice and a confidence; any other code reads by the four error meanings below.',
71
+ 'Its documented response:',
72
+ '{"model":"jev-1.13.0","answers":{"department":{"type":"choice","choice":"billing","probabilities":{"billing":0.88,"technical":0.12,"sales":0.0},"confidence":0.81}},"usage":{"input_tokens":318,"output_tokens":34}}',
73
+ 'choice: "The highest-probability option."',
74
+ 'probabilities: "Every option mapped to its probability (floats that sum to 1)."',
75
+ 'confidence: "How certain the model is, derived from probabilities."',
76
+ '401: "Missing or invalid API key. Check the `Authorization` header."',
77
+ '422: "The request body failed validation — for example a missing required field or a malformed question. The body details the offending field."',
78
+ '429: "You have exceeded your rate limit. Back off and retry after a short delay."',
79
+ '529: "TypeSafe is temporarily overloaded. Retry after a short delay."',
80
+ 'Then give the agent this prompt: using the TypeSafe skill, route these three tickets to billing, technical or sales, one request each, and print each choice and confidence — "I was charged twice this month.", "The app crashes when I upload a file.", "Is there a discount for a yearly plan?".',
81
+ 'Success: three choices, each with a confidence.',
82
+ ];
83
+ const LIMITS = 'Each request stays within the vendor limits: 255 options, 64k tokens, 32k for the state plus the longest question.';
84
+ const HINT = 'The answer is a hint the agent checks, never a gate; every candidate text is sent to the vendor.';
85
+ const PROMPTS = [
86
+ `(a) A red gate log: give each failing gate's own lines ids and ask one choice of the first real error per failing gate. ${LIMITS} ${HINT}`,
87
+ `(b) Council findings against the decided register: for each finding, ask a choice of the register id it repeats, or none. ${LIMITS} ${HINT}`,
88
+ `(c) Candidate paragraphs with ids: ask one noul each that the paragraph restates a named rule. ${LIMITS} ${HINT}`,
89
+ ];
90
+
91
+ const valueAt = (argv, index, flag) => {
92
+ const value = argv[index + 1];
93
+ if (value === undefined || value === '' || value.startsWith('-')) throw fail(2, `${flag} takes a value`);
94
+ return value;
95
+ };
96
+ const parseArgv = (argv) => {
97
+ if (argv.includes('--help') || argv.includes('-h')) {
98
+ if (argv.length !== 1) throw fail(2, '--help is answered only when it is the whole invocation');
99
+ return { help: true };
100
+ }
101
+ return argv.reduce((parsed, arg, index) => {
102
+ if (parsed.skip) return { ...parsed, skip: false };
103
+ if (arg === '--dir') return { ...parsed, dir: valueAt(argv, index, arg), skip: true };
104
+ if (arg === '--json') return { ...parsed, json: true };
105
+ throw fail(2, `unknown argument "${arg}" — run with --help`);
106
+ }, { help: false, dir: '.', json: false, skip: false });
107
+ };
108
+
109
+ const statIs = (path, kind) => {
110
+ try { return kind === 'file' ? statSync(path).isFile() : statSync(path).isDirectory(); } catch { return false; }
111
+ };
112
+ const skillPaths = (dir, home) => [...new Set([join(dir, '.claude', 'skills'), join(dir, '.agents', 'skills'),
113
+ join(home, '.claude', 'skills'), join(home, '.codex', 'skills'), join(home, '.cursor', 'skills')]
114
+ .map((root) => join(root, SKILL_FILE)))];
115
+ export const keySet = (env) => typeof env[KEY_VARIABLE] === 'string' && env[KEY_VARIABLE].trim() !== '';
116
+ const profileOf = (env) => (typeof env.SHELL === 'string' && Object.hasOwn(PROFILES, basename(env.SHELL)) ? PROFILES[basename(env.SHELL)] : null);
117
+
118
+ const renderSteps = (found, set, profile) => [
119
+ ['STEP 1 — the key', KEY_GET, ...(profile ? [KEY_RUN, KEY_LINE.replace('PROFILE', profile)] : [KEY_EDITOR]), KEY_RESTART,
120
+ KEY_NEVER, set ? `key: ${KEY_VARIABLE} set.` : keyNotSet(profile)],
121
+ ['STEP 2 — the vendor skill', ...INSTALL,
122
+ ...(found.length ? found.map((path) => `skill: found at ${path}`) : NOT_SEEN)],
123
+ ['STEP 3 — the first request', ...FIRST_USE],
124
+ ];
125
+
126
+ export const main = (argv, io = {}) => {
127
+ const log = io.log ?? console.log;
128
+ const error = io.error ?? console.error;
129
+ const parsed = (() => {
130
+ try { return parseArgv(argv); } catch (err) { error(err.message); return null; }
131
+ })();
132
+ if (parsed === null) return 2;
133
+ if (parsed.help) { log(HELP); return 0; }
134
+ const dir = resolve(io.cwd ?? process.cwd(), parsed.dir);
135
+ if (!statIs(dir, 'directory')) { error(`${dir} is not a directory`); return 1; }
136
+ const found = skillPaths(dir, io.home ?? homedir()).filter((path) => statIs(path, 'file'));
137
+ const env = io.env ?? process.env;
138
+ const set = keySet(env);
139
+ const profile = profileOf(env);
140
+ const steps = renderSteps(found, set, profile);
141
+ log(parsed.json
142
+ ? JSON.stringify({ schema: SCHEMA, command: 'jev', dir, text: JEV_TEXT, skill: { found }, key: { set, profile },
143
+ steps, prompts: PROMPTS }, null, 2)
144
+ : [...JEV_TEXT, ...steps.flat(), 'WHERE IT PAYS IN THIS WORKFLOW', ...PROMPTS].join('\n'));
145
+ return 0;
146
+ };
147
+
148
+ if (isDirectRun(import.meta.url)) process.exitCode = main(process.argv.slice(2));
@@ -94,6 +94,7 @@ import {
94
94
  ACKS_WORKTREES_DIR_KEY,
95
95
  ACKS_COVERAGE_DOMAIN_KEY,
96
96
  ACKS_SOURCE_SIZE_COPY_KEY,
97
+ ACKS_JEV_CONNECT_KEY,
97
98
  ACK_LANES,
98
99
  factFingerprint,
99
100
  readAckValue,
@@ -101,9 +102,12 @@ import {
101
102
  import { ADOPTION, STORE_DIR_REL as SPEC_STORE_DIR_REL, SPEC_ADOPTION_LANE, declineFingerprint, readDeclineAck, surveySpecAdoption } from './spec-adoption.mjs';
102
103
  import { ENSURE_OPS } from './ensure-vocabulary.mjs';
103
104
  import { composeProfileGapScreen } from './profile-gap-screen.mjs';
105
+ import { keySet } from './jev-guide.mjs';
104
106
 
105
107
  // The upgrade ensure that seeds the spec store — the not-adopted item's apply; pinned to the vocabulary.
106
108
  const SPEC_LAYER_ENSURE = ENSURE_OPS.includes('specs') ? 'specs' : null;
109
+ const JEV_CONNECT_DECLINED = 'jev-connect:declined';
110
+ const JEV_CONNECT_DECLINE = factFingerprint(JEV_CONNECT_DECLINED);
107
111
 
108
112
  export { ACKS_FILE, ACKS_LANE_KEY, ACKS_WORKTREES_DIR_KEY, ACKS_COVERAGE_DOMAIN_KEY, ACKS_SOURCE_SIZE_COPY_KEY, ACK_LANES, factFingerprint };
109
113
 
@@ -201,6 +205,7 @@ export const SEVERITIES = Object.freeze({
201
205
  // the decline. Neither arm can leave the flow-optimal line standing — an offer is still an item.
202
206
  'spec-adoption': SEVERITY_OPTIONAL,
203
207
  'profile-gap': SEVERITY_OPTIONAL,
208
+ 'jev-connect': SEVERITY_OPTIONAL,
204
209
  'spec-adoption.adopting': SEVERITY_OPTIONAL,
205
210
  });
206
211
  // The per-item render tags (frozen presentation data, same language contract as the templates).
@@ -278,6 +283,7 @@ export const WHATS = Object.freeze({
278
283
  'worktrees-dir': 'write access to the worktrees parent dir {dir} is not confirmed — provision may still stop',
279
284
  'spec-adoption': 'feature-spec store absent (docs/ai/specs) — no feature contract can govern a plan here yet; seed the store, or record the decline',
280
285
  'profile-gap': '{what}',
286
+ 'jev-connect': 'TYPESAFE_API_KEY is not set on this host — Jev (TypeSafe), a typed decision model, is not connected machine-wide',
281
287
  'spec-adoption.adopting': 'feature-spec store: {n} draft spec(s), no live contract — nothing governs a plan through it yet; land a live contract, or record the decline',
282
288
  });
283
289
 
@@ -339,6 +345,7 @@ export const BENEFITS = Object.freeze({
339
345
  'worktrees-dir': 'parallel features — the host-specific write allowance or terminal fallback is surfaced before provision',
340
346
  'spec-adoption': 'contracts — a plan names the contract it builds to, and a change to a governed slice is visible at review instead of after it',
341
347
  'profile-gap': 'full flow — each difference from the reference profile is previewed by its own writer; a declined one returns only at a lineage step',
348
+ 'jev-connect': 'decisions — a typed choice with a confidence in under a second for your code and the agent\'s scripts, once for every project here',
342
349
  });
343
350
 
344
351
  // ── the CLOSED opt-in capability registry (OPT-IN-SHIPS-INVISIBLE) ──────────────────────────────
@@ -386,6 +393,7 @@ export const OPT_IN_CAPABILITIES = Object.freeze([
386
393
  // its adoption state is declared where the store is seeded.
387
394
  { id: 'spec-adoption', mode: 'upgrade', advisorKey: 'spec-adoption' },
388
395
  { id: 'full-flow-profile', mode: 'upgrade', advisorKey: 'profile-gap' },
396
+ { id: 'jev-connect', mode: 'jev', advisorKey: 'jev-connect' },
389
397
  { id: 'adr-store-migration', mode: 'migrate-adr-store', advisorKey: 'adr-store-migration' },
390
398
  { id: 'review-recipe', mode: 'set-recipe', advisorKey: 'review-recipe' },
391
399
  // The execute slot is a DISTINCT opt-in from the review slot, and the same probe reports both —
@@ -1305,7 +1313,7 @@ const readReadLaneToggle = (root, deps) => {
1305
1313
  // D3: the risk-marked keys — every key here has a per-item posture note in the mode doc, surfaced
1306
1314
  // at the consent moment; the static contract test asserts EXACT bidirectional coverage
1307
1315
  // (risk-marked keys == mode-doc note keys — a dropped note goes red, not silent).
1308
- export const RISK_NOTED_KEYS = Object.freeze(['sandbox-lane', 'read-lane', 'worktrees-dir', 'adr-store-migration', 'gates-inert', 'source-size', 'gate-hook', 'mcp-channel', 'spec-adoption', 'enforcement', 'profile-gap']);
1316
+ export const RISK_NOTED_KEYS = Object.freeze(['sandbox-lane', 'read-lane', 'worktrees-dir', 'adr-store-migration', 'gates-inert', 'source-size', 'gate-hook', 'mcp-channel', 'spec-adoption', 'enforcement', 'profile-gap', 'jev-connect']);
1309
1317
 
1310
1318
  // The feature-spec layer's adoption state (contract: kit/spec-adoption). The canon lets a plan cite
1311
1319
  // zero governing specs while a project adopts the layer, and nothing ever said whether adoption had
@@ -1600,6 +1608,20 @@ const probeMcpChannel = ({ root, deps, add, skip }) => {
1600
1608
  }
1601
1609
  };
1602
1610
 
1611
+ // The Jev offer (contract: kit/jev-guide, part jev-offer). The key is judged first, through the
1612
+ // guide's own rule over the injected environment only; the ack store is read only when it is not set.
1613
+ export const probeJevConnect = ({ root, deps, add, skip }) => {
1614
+ try {
1615
+ if (keySet(deps.getenv ?? {})) return;
1616
+ if (readAckValue(root, deps, ACKS_JEV_CONNECT_KEY) === JEV_CONNECT_DECLINE) return;
1617
+ const decline = `node ${q(toolPath('ack-write.mjs'))} --lane jev-connect --fingerprint ${JEV_CONNECT_DECLINE} --cwd ${q(root)}`;
1618
+ add('jev-connect', WHATS['jev-connect'], `node ${q(toolPath('jev-guide.mjs'))} --dir ${q(root)} --json`, 'jev-connect',
1619
+ `HAND-APPLY alternative (instead of the apply, never after it): decline the offer by recording it — ${decline}`);
1620
+ } catch (err) {
1621
+ skip('jev-connect', err);
1622
+ }
1623
+ };
1624
+
1603
1625
  export const probeProfileGaps = ({ root, deps, add, skip }) => {
1604
1626
  try {
1605
1627
  const { gaps, skips } = composeProfileGapScreen({ root, deps });
@@ -1632,6 +1654,7 @@ const PROBES = Object.freeze([
1632
1654
  probeWorktreesDir,
1633
1655
  probeMcpChannel,
1634
1656
  probeSpecAdoption,
1657
+ probeJevConnect,
1635
1658
  probeProfileGaps,
1636
1659
  ]);
1637
1660
 
@@ -1758,7 +1781,7 @@ export const main = (argv, ctx = {}) => {
1758
1781
  }
1759
1782
  })();
1760
1783
  if (st == null || !st.isDirectory()) throw Object.assign(new Error(`--cwd is not a directory: ${cwd}`), { exitCode: 1 });
1761
- const result = buildRecommendations({ cwd, deps: ctx.deps ?? {} });
1784
+ const result = buildRecommendations({ cwd, deps: ctx.deps ?? { getenv: process.env } });
1762
1785
  if (json) return { code: 0, stdout: JSON.stringify(result, null, 2), stderr: '' };
1763
1786
  return { code: 0, stdout: formatRecommendations(result), stderr: '' };
1764
1787
  } catch (err) {