From 3a59bebff0d174a493f83ed74963f3789a6dd25c Mon Sep 17 00:00:00 2001 From: johnmicheal-lua Date: Sun, 11 Oct 2026 15:36:51 +0200 Subject: [PATCH 1/2] feat(decisions): /lua-decisions, /lua-new decision and the decisions knowledge file; 1.10.0 - commands/lua-decisions.md: list, versions, run (--message/--state, --provider, --model, --min-confidence), publish, delete - lib/knowledge/decisions.md: builders, result shape, routing and OpenRouter rules, LuaDecision lifecycle, verbs, exits, errors, billing - permissions: decisions list/versions/run allowed, publish/delete ask; mirror test rows - lua-new and lua-skill-builder: the decision type, file convention, registration, compile-only verification - lua-logs: --type decisions; lua-debug: DecisionError branch and allowlist; primitives and decision-trees routing; cli-reference row and docs map - version 1.10.0 in plugin.json, package.json, marketplace.json and the MCP server stamps --- .claude-plugin/marketplace.json | 2 +- README.md | 2 +- docs/USER_GUIDE.md | 3 + .../.claude-plugin/plugin.json | 2 +- plugins/lua-agent-builder/CHANGELOG.md | 23 +++ plugins/lua-agent-builder/README.md | 6 +- plugins/lua-agent-builder/agents/lua-debug.md | 3 + .../agents/lua-skill-builder.md | 5 +- .../commands/lua-decisions.md | 52 ++++++ .../lua-agent-builder/commands/lua-logs.md | 2 + plugins/lua-agent-builder/commands/lua-new.md | 9 +- .../lib/knowledge/cli-reference.md | 3 +- .../lib/knowledge/decision-trees.md | 1 + .../lib/knowledge/decisions.md | 169 ++++++++++++++++++ .../lib/knowledge/primitives.md | 2 +- .../lib/permissions-template.json | 7 +- .../mcp/lua-platform/package-lock.json | 4 +- .../mcp/lua-platform/package.json | 2 +- .../mcp/lua-platform/src/api-client.mjs | 2 +- .../mcp/lua-platform/src/server.mjs | 6 +- plugins/lua-agent-builder/package.json | 2 +- .../test/lib/permissions-mirror.test.mjs | 9 + 22 files changed, 295 insertions(+), 21 deletions(-) create mode 100644 plugins/lua-agent-builder/commands/lua-decisions.md create mode 100644 plugins/lua-agent-builder/lib/knowledge/decisions.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8f9f034..ab33463 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "name": "lua-agent-builder", "source": "./plugins/lua-agent-builder", "description": "Build, test, and deploy Lua AI agents from inside Claude Code", - "version": "1.9.1", + "version": "1.10.0", "homepage": "https://github.com/lua-ai-global/claude-code-lua-plugin#readme", "repository": "https://github.com/lua-ai-global/claude-code-lua-plugin.git", "license": "MIT", diff --git a/README.md b/README.md index d3cf1e5..d1a20c2 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Then `/lua-auth`: an existing credential is kept; a new login runs `lua auth con | Plugin | Description | |---|---| -| [`lua-agent-builder`](./plugins/lua-agent-builder/) | 22 slash commands, 10 subagents, 13 hooks, a 7-file knowledge base verified against lua-cli source (3.33.0 base; 1.3.0 added per-step model classes and the workflow autonomy envelope from lua-cli 3.36.0, 1.4.0 the Job-tier billing rules and the lua-cli 3.37.0 cost read-outs, 1.5.0 log drains and the `lua logs` read window from lua-cli 3.38.0, read from `main`; 1.6.0 headless mode and a hardened production-gate parser; 1.7.0 `/lua-devices`, device credentials that never reach the conversation, and a re-check against lua-cli 3.44.0 / 3.45.0; 1.8.0 web apps (Lua Apps); 1.9.0 the full QA suite, `/lua-qa full`), a local read-only platform MCP server and the public docs MCP | +| [`lua-agent-builder`](./plugins/lua-agent-builder/) | 23 slash commands, 10 subagents, 13 hooks, a 9-file knowledge base verified against lua-cli source (3.33.0 base; 1.3.0 added per-step model classes and the workflow autonomy envelope from lua-cli 3.36.0, 1.4.0 the Job-tier billing rules and the lua-cli 3.37.0 cost read-outs, 1.5.0 log drains and the `lua logs` read window from lua-cli 3.38.0, read from `main`; 1.6.0 headless mode and a hardened production-gate parser; 1.7.0 `/lua-devices`, device credentials that never reach the conversation, and a re-check against lua-cli 3.44.0 / 3.45.0; 1.8.0 web apps (Lua Apps); 1.9.0 the full QA suite, `/lua-qa full`; 1.10.0 decisions, `/lua-decisions` and `/lua-new decision` from lua-cli 3.48.0 / 3.49.2), a local read-only platform MCP server and the public docs MCP | ## Quick walkthrough diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 2005fdc..b13e4a3 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -51,6 +51,8 @@ If you just want to start: [Installation](#installation) → [Your first agent]( `/lua-doctor` checks all of these and offers consent-gated fixes. Platforms: macOS 14+, Ubuntu 22.04+, Windows 11; CI runs the suite on all three with Node 18 and 20. +New in 1.10.0: **decisions.** A decision is one call that takes some state and typed questions and returns typed answers with probabilities: the odds that something is true, a choice with its confidence, or a score on a scale. `/lua-new decision ` writes a `LuaDecision` with literal questions and registers it; `/lua-push decision` stages a version; `/lua-decisions` lists the agent's decisions, shows their versions, runs one on a message or JSON state (on the version's model, or `--model ` for any of the thirteen decision models, Jev and OpenAI included), publishes a version (the rollback) or deletes one. Reads and runs go at once; publish and delete confirm once through the Bash prompt. Needs lua-cli 3.48.0; `--model` and the OpenRouter ids need 3.49.2. + New in 1.9.0: **the full QA suite.** `/lua-qa full` runs at a tier: `smoke` (a 30-minute cap from the moment you approve the plan), `medium` (the default, 1 to 2 hours) or `production-ready` (3 to 5 hours, ending in a release gate). It maps the agent into diagrams you confirm and infers the qualifying answers and metrics from the code, citing a `file:line` for each (`--interview` asks you instead). Then it plays customer personas several times each plus a red team, runs offline workflow flow tests, direct tool tests and (outside smoke) a stress test in parallel, grades every run with two independent graders (one in smoke), clusters the failures by root cause and writes a PDF, HTML and JSON report. Bare `/lua-qa` (or `/lua-qa quick`) is the pass from earlier releases, unchanged and with no new question. New in 1.7.0: **devices.** `/lua-devices` connects a Raspberry Pi, a laptop or a Pico W to the agent. It helps you choose between a self-describing client and a `defineDevice` declaration. With lua-cli 3.45.0 it issues a **device credential** straight into a git-ignored, mode-600 `.env.device` that the conversation never sees (a scoped personal API key is refused by the device gateway). It writes a Node, Python or MicroPython client, pushes, and tests with `lua devices status`, `test --command` and `test-trigger --trigger`. Every 3.45-only step names its lua-cli 3.44 fallback. The same release re-checks the plugin against lua-cli 3.44.0, where `lua push agent` stages the persona and `lua push all` no longer activates workflows, and gates the new non-interactive `lua skills production deploy`. @@ -172,6 +174,7 @@ Chat-composed workflows can't be deployed from the CLI (`WORKFLOW_DYNAMIC`); `/l | `/lua-chat` | `lua chat --ci -e … -m … -t` | always an explicit thread | | `/lua-logs` | `lua logs --ci --type … --json` | the real 18-source `--type` list (`mastra` is not valid); ⏳ 3.38.0 `--since` / `--until` (ISO instant or `15m`/`2h`/`7d`, resolved by the server's clock), `--environment production\|sandbox`, `--follow` (polls ~2 s, refuses `--page`) | | `/lua-drains` | `lua drains list\|status\|deliveries\|create\|update\|delete\|test\|verify\|pause\|resume\|rotate-secret` | ⏳ 3.38.0. Reads run at once; the seven configuration verbs confirm once through the Bash prompt. Needs `logs:manage` (a sensitive scope). The signing secret is printed once by the platform and never stored by the plugin; header values are prompted or read from an environment variable with `--header-from-env NAME=ENV_VAR`, never typed on a command line | +| `/lua-decisions` | `lua decisions list\|versions\|run\|publish\|delete`, `lua logs --type decisions` | ⏳ 3.48.0. `run` takes `--message` or `--state` and, ⏳ 3.49.2, `--provider` / `--model ` (any decision model, including the eleven served through OpenRouter) / `--min-confidence`; list/versions/run go at once, publish and delete confirm once through the Bash prompt; a new decision is `/lua-new decision`, a push is `/lua-push decision` | | `/lua-devices` | `lua devices list\|status\|credential\|test\|test-trigger\|enable\|disable\|remove`, `lua push device\|device-trigger`, `lua logs --type device\|device-trigger` | guided `setup` (credential → client → push → test); the credential always goes to a git-ignored file via `--out`; reads run at once, everything else confirms once through the Bash prompt; ⏳ 3.45.0 verbs have 3.44 fallbacks | | `/lua-env` | `lua env --list \| -k KEY -v VALUE \| -k KEY --delete` | environment + key + value collected once; the Bash prompt is the confirmation; the value is never echoed, listings show masked values | | `/lua-integrations` | `lua integrations available\|list\|info\|webhooks …\|mcp …` | read-only verbs run at once; disconnect/convert/webhooks/mcp mutations confirm once via the Bash prompt; `connect`/`update` (browser OAuth) are printed for your terminal | diff --git a/plugins/lua-agent-builder/.claude-plugin/plugin.json b/plugins/lua-agent-builder/.claude-plugin/plugin.json index 89ce190..da0e49d 100644 --- a/plugins/lua-agent-builder/.claude-plugin/plugin.json +++ b/plugins/lua-agent-builder/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "lua-agent-builder", - "version": "1.9.1", + "version": "1.10.0", "description": "Build, test, and deploy Lua AI agents from inside Claude Code", "author": { "name": "Lua AI", diff --git a/plugins/lua-agent-builder/CHANGELOG.md b/plugins/lua-agent-builder/CHANGELOG.md index 6139fe9..f0d8f38 100644 --- a/plugins/lua-agent-builder/CHANGELOG.md +++ b/plugins/lua-agent-builder/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to the `lua-agent-builder` plugin. Versions follow the tag `release-prod.yml` cuts from `package.json` (`v`). lua-cli is a TypeScript SDK/CLI; it is unrelated to the Lua programming language. +## 1.10.0 — 2026-10-11 + +**Decisions: `/lua-decisions`, `/lua-new decision`, and a knowledge file for the Decisions primitive** (lua-cli 3.48.0; `--model` and the OpenRouter ids from lua-cli 3.49.2). + +A decision is one call that takes some state and typed questions (`Decisions.odds`, `Decisions.choice`, `Decisions.score`) and returns typed answers with probabilities, from any agent code. A `LuaDecision` is the named, versioned form: `lua push` stages a version, the dashboard edits and publishes, `lua decisions publish` rolls back, and `Decisions.run('', state)` keeps asking the current version. Thirteen models answer behind one shape: Jev (Lua's default), OpenAI, and eleven decision models served through OpenRouter by `vendor/model` id. + +### New + +- **`/lua-decisions [list | versions | run | publish | delete ]`** (`commands/lua-decisions.md`). `run` takes `--message ''` or `--state ''` and the per-call overrides `--provider`, `--model ` and `--min-confidence`, and reports every answer by its type (odds, choice with confidence and `uncertain`, score with its level, or refused) with the provider, the dated model id, the routing rule, duration, tokens, cache status and the cost in actions. `publish` and `delete` go through the Bash prompt once (`--force`, since the CLI's own y/N cannot be answered from a slash); the slash never adds an AskUserQuestion on top. +- **`/lua-new decision `** writes `src/decisions/.ts` with literal questions (the one shape the compiler can read), registers it in `decisions: [...]`, compiles, reads the manifest entry back, and names the push and publish steps; the builder shows the typed caller the user will write and why `answer.type` is checked before `.odds` / `.choice` / `.score`. +- **`lib/knowledge/decisions.md`**: the builders and their limits, the result shape, providers and routing (what `auto` picks, when a fallback runs and what it costs, why a pinned provider never switches), the OpenRouter rules (a `vendor/model` id pins openrouter; `provider: 'openrouter'` needs a model; `typesafe/…` and `openai/…` ids are refused with the provider to use; unknown or data-retaining ids fail `decision_rejected` with no fallback; images reach every model), the `LuaDecision` lifecycle (staged by push, current by promote or publish, 1.0.1 on the first push, dashboard drafts never pinned), the five verbs with aliases and exit codes, the error codes, sharing and caching, the `decisions` log source, and billing (0.005 actions on Jev, 0.01 on OpenAI or OpenRouter, free when cached, failed or cancelled). + +### Changed + +- **Permissions** (`lib/permissions-template.json`, mirrored in `test/lib/permissions-mirror.test.mjs`): `lua decisions list|versions|run` are allowed (`run` is one billed call that changes no configuration); `lua decisions publish|delete` sit in `ask`, the single confirmation `/lua-decisions` relies on. `lua push decision` rides the generic push allow — a pushed decision is staged only. Not in the tokenizer: making a decision version current is agent configuration, not a deploy. +- **`/lua-logs`** documents `--type decisions` (one row per call: model, provider, rule, answers with probabilities, tokens, cost, cache status, error code). +- **The debug subagent** (`agents/lua-debug.md`) reads a `DecisionError` by code: `decision_invalid` names the field, `decision_not_found` is a version that was never made current (fix with publish or promote, not code), `decision_rejected` is the model refusing the request and never falls back, the 503 family is the provider side and the SDK never retries. `lua decisions list|versions` join its allowlist. +- **`/lua-new`** accepts `decision` (aliased from `decisions`) with one extra question, "what should it decide, and what are the possible answers?"; the builder (`agents/lua-skill-builder.md`) reads `decisions.md`, writes the file by convention, registers it in `decisions`, and compile-verifies it (there is no `lua test` type). +- **`primitives.md` §16 and `decision-trees.md`** route "a judgment the code branches on" to `Decisions.ask` or a `LuaDecision`, next to `AI.generate` for prose. +- **`cli-reference.md`** gains the `lua decisions` row in §4 and the two SDK pages in the docs map. + +Versioning: 1.9.1 is on `main` and tagged, so this is 1.10.0. Nothing else is open that declares a version. + ## 1.9.1 — 2026-10-08 **`/lua-qa full`: report correctness fixes from the first three-tier trial.** The suite ran smoke, medium and production-ready on a test agent (Pageturner Books: 7 tools, 4 workflows, one of them a `foreach`). Four defects changed what the report said. diff --git a/plugins/lua-agent-builder/README.md b/plugins/lua-agent-builder/README.md index c7a9750..190fea1 100644 --- a/plugins/lua-agent-builder/README.md +++ b/plugins/lua-agent-builder/README.md @@ -21,11 +21,11 @@ New login runs in your own terminal (`lua auth configure`) — the plugin never plugins/lua-agent-builder/ ├── .claude-plugin/plugin.json # plugin manifest ├── .mcp.json # lua-platform (local stdio) + lua-docs (https://docs.heylua.ai/mcp) -├── commands/ # 22 slash commands +├── commands/ # 23 slash commands ├── agents/ # 10 subagents (architect, skill-builder, debug, deploy-pilot, qa, qa-cartographer, qa-player, qa-grader, qa-analyst, qa-reporter) ├── hooks/ # 12 Node ESM hooks + hooks.json ├── lib/ -│ ├── knowledge/ # primitives, workflows, cli-reference, integrations, decision-trees, log-drains, devices +│ ├── knowledge/ # primitives, workflows, cli-reference, integrations, decision-trees, log-drains, devices, web-apps, decisions │ │ └── qa/ # /lua-qa full prompts: rubric, ICP cards, player, red team, graders, analyst, fix-locus, mechanics, qualifying questions │ ├── qa/ # /lua-qa full helpers behind one entry, lib/qa/cli.mjs (recorder, checks, discovery + SVG, report, Workflow script) │ ├── permissions-template.json# allow/ask/deny rules /lua-doctor merges into .claude/settings.json @@ -53,6 +53,7 @@ plugins/lua-agent-builder/ | `/lua-chat` | One-shot `lua chat --ci -e -m … -t` on an isolated thread | | `/lua-logs` | `lua logs --ci --json` with the real 18-source `--type` list and ⏳ the 3.38.0 read window (`--since` / `--until` / `--environment` / `--follow`) | | `/lua-drains` | ⏳ 3.38.0 log drains: `lua drains list\|status\|deliveries\|create\|update\|delete\|test\|verify\|pause\|resume\|rotate-secret`; reads run at once, the seven config verbs confirm once, the signing secret is never stored | +| `/lua-decisions` | ⏳ 3.48.0 named decisions (`LuaDecision`): `lua decisions list\|versions\|run\|publish\|delete`; `run` takes a message or JSON state and, ⏳ 3.49.2, `--model ` for any of the thirteen decision models (Jev, OpenAI, eleven through OpenRouter); list/versions/run go at once, publish (rollback) and delete confirm once | | `/lua-devices` | Hardware and local machines: self-describing vs `defineDevice`, ⏳ 3.45.0 `lua devices credential --out` (the secret goes to a git-ignored mode-600 file, never the conversation), Node / Python / Pico W client scaffolds, `push device` / `device-trigger`, `status`, ⏳ 3.45.0 `test --command` / `test-trigger --trigger`, `lua logs --type device\|device-trigger`, troubleshooting — every 3.45-only verb has a 3.44 fallback | | `/lua-env` | `lua env --list \| -k KEY -v VALUE \| -k KEY --delete`; the Bash prompt is the confirmation, values never echoed | | `/lua-integrations` | `lua integrations available\|list\|info\|webhooks …\|mcp …`; read-only verbs run at once, mutations confirm once, OAuth connects go to your terminal | @@ -69,6 +70,7 @@ plugins/lua-agent-builder/ - **Headless mode** — `LUA_PLUGIN_HEADLESS=1` (for `claude -p` in the Lua Job tier or CI): no hook message points at a slash command, the `LUA_DEPLOY_CONFIRMED=1` prefix is void (every production verb is blocked) and the post-deploy smoke ping is skipped. See [Running in the Lua Job tier](../../docs/JOB_TIER.md). - **`--auto-deploy`** is denied and blocked unconditionally. - **Log drains** (⏳ lua-cli 3.38.0) are ORGANIZATION configuration, not a deploy: `lua drains list|status|deliveries|test` are allowed, and `create|update|delete|verify|pause|resume|rotate-secret` sit in the `ask` tier — that prompt is `/lua-drains`'s single confirmation. They are deliberately **not** in `lib/tokenizer.mjs`: none of them changes what runs in production, and `LUA_DEPLOY_CONFIRMED=1` would be the wrong sentence for a log-shipping change. No secret ever reaches a command line — a header value is prompted or read from an environment variable (`--header-from-env NAME=ENV_VAR`), and the HMAC signing secret is minted server-side and printed exactly once. +- **Decisions** (⏳ lua-cli 3.48.0) are AGENT configuration, not a deploy: `lua decisions list|versions|run` are allowed (`run` is one billed call that changes nothing), and `publish` (makes a version current for every caller) and `delete` sit in the `ask` tier — that prompt is `/lua-decisions`'s single confirmation. `lua push decision` stages only and rides the generic push allow; a staged version goes live through `lua version promote` (gated) or `lua decisions publish` (ask). - **Devices** are not part of agent versions and are not deploy verbs: a pushed `defineDevice` is live on the next turn, so `lua push device` / `device-trigger` sit in the `ask` tier (above the generic push allow rule), as do `lua devices enable|disable|remove|test|test-trigger|credential` and their aliases; `list` / `status` are allowed. A device-trigger is published only by `--auto-deploy`, which stays denied — `/lua-devices` prints that line for your own terminal. - **Web apps** (lua-cli 3.42.0+) run their routes as you against the agent's live `Data`, locally too — there is no test database. The plugin runs `GET` routes freely and asks once before any route that writes; it never starts `lua apps dev` (it prints that for your own terminal). Only `lua apps new ` and four npm commands run without a prompt — `npm --prefix src/apps//web install --ignore-scripts [@lua-ai-global/app-client]`, `run typecheck`, `run build` — and only in that exact form: the `approve-web-app` hook matches them with anchored regexes rather than permission globs (a glob's `*` would also match an extra package, a second `--prefix`, or anything after the app name). A web-app push is staged only; `/lua-deploy webapp` promotes a new agent version and stops before promoting if that version would also make other staged primitives live. - **Credential isolation** — `lua auth configure|key|logout` are denied for the model; login happens in your terminal. A device credential is only ever issued with `--out ` (the `block-device-secret` hook blocks the printing form), into a git-ignored mode-600 file the plugin never reads back. diff --git a/plugins/lua-agent-builder/agents/lua-debug.md b/plugins/lua-agent-builder/agents/lua-debug.md index 60fae9d..de95cc7 100644 --- a/plugins/lua-agent-builder/agents/lua-debug.md +++ b/plugins/lua-agent-builder/agents/lua-debug.md @@ -40,6 +40,7 @@ A `lua compile --ci`, `lua test --ci` or `lua push` invocation failed, or a work - **Workflow run failed (exit 4)** → `lua workflows status --steps --json`: the failing step's `error.code`; `binding_unresolved`/`input_schema_invalid`/`credentials_unresolved` park pre-dispatch. Re-test offline with `lua test --ci workflow --name --input '' --from-run `: the driver fetches that run and each planned step from the API, seeds every `completed` step whose ancestors are all seeded (latest attempt wins) with its output and effects, and re-drives from the first pending step — so only the failing step and what follows re-execute (`[from-run] N step(s) seeded from `). Exit `3` = the run was not found; exit `2` `[from-run] graph differs (N steps changed) — pass --force to seed anyway` = your compiled `graphHash` no longer matches the run's (you changed the graph) — add `--force` to seed the steps that still line up. - **"Our logs stopped arriving in Datadog / our receiver"** (⏳ lua-cli 3.38.0 or later; facts in `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/log-drains.md`) → this is a **log drain**, an organization resource, and nothing about the agent's code. Read `lua drains status --json`: `state` (`pending_verification` buffers and never delivers — the endpoint changed and nobody re-verified; `paused` with `pauseReason: 'quota'` is the 150% rung of the quota ladder; `paused` with `'auto'` is 24 h without a success), `health.lastStatusCode` / `health.lastError`, `health.backlog`, and `quota.degradation` (at 100% `debug` is dropped, at 125% `info` too — `warn` and `error` are never dropped before the drain pauses). Then `lua drains deliveries --limit 20 --json` for the per-attempt `errorClass` (`network timeout dns ssrf redirect http_4xx http_429 http_5xx rejected partial encode`). ⚠ `lua drains status` exits **2** both for a usage error *and* for "some drain is `failing`" — decide from `drains[].state`, never from the exit code. Exit 10 is the missing **`logs:manage`** scope, which is sensitive (`logs:*` does not satisfy it) and is re-minted by the user in their own terminal. Exit 3 on every verb means the feature is not rolled out to that organization. Fixing a drain is `/lua-drains`, not an edit here: **never** print a signing secret, and never put a header value on a command line (`--header-from-env =` is the CI form). + - **A `DecisionError` from `Decisions.ask` / `Decisions.run`** (⏳ lua-cli 3.48.0 or later; facts in `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/decisions.md`) → read `code` and `decisionId`, then the row with `lua logs --ci --json --type decisions --limit 20`. `decision_invalid` (400) names the field: a question built outside `Decisions.odds|choice|score`, options outside 2–64, levels outside 2–10, state over 120,000 chars, images over 6 MB, `provider: 'openrouter'` without a `model`, or a `model` of another provider (a `typesafe/…` / `openai/…` id on openrouter says which provider to set instead). `decision_not_found` (404) is a `Decisions.run` name the agent does not declare, a deleted decision, or one pushed but never made current — `lua decisions versions --json` shows whether any version is current; the fix is `lua decisions publish ` (`/lua-decisions`, ask tier) or `lua version promote` (`/lua-deploy`), never a code change. `decision_rejected` (422) is the model refusing the request itself (Jev pinned with images, an unknown or data-retaining OpenRouter id, state over the model's limit): quote the upstream message; it never falls back. `decision_timeout` / `decision_unavailable` / `decision_disabled` (503) are the provider side — the SDK never retries, `fallback` already ran when `rule` is `'fallback'`; suggest a longer `timeoutMs` (≤ 15,000) only when `durationMs` on nearby rows is near the budget. A `decision_cancelled` on every call is the caller going away, not the model. A compile error naming a decision export means the `LuaDecision` was built by a helper or lists an openrouter id of a direct provider — rewrite it as a literal `new LuaDecision({...})`. 4. **Unknown message?** Search the docs with `mcp__plugin_lua-agent-builder_lua-docs__search_lua_cli ""` or `mcp__plugin_lua-agent-builder_lua-docs__query_docs_filesystem_lua_cli "rg -n '' /"`; `WebFetch https://docs.heylua.ai/cli/troubleshooting` is the fallback. Never guess at internals. @@ -59,6 +60,8 @@ A `lua compile --ci`, `lua test --ci` or `lua push` invocation failed, or a work - `lua logs --ci [args]` - `lua drains status *` - `lua drains deliveries *` +- `lua decisions list --json` +- `lua decisions versions * --json` - `lua workflows status * --steps --json` - `lua workflows logs *` - `git log --oneline -20` diff --git a/plugins/lua-agent-builder/agents/lua-skill-builder.md b/plugins/lua-agent-builder/agents/lua-skill-builder.md index 2ba136c..77cd1f3 100644 --- a/plugins/lua-agent-builder/agents/lua-skill-builder.md +++ b/plugins/lua-agent-builder/agents/lua-skill-builder.md @@ -12,6 +12,7 @@ You receive `{ type, name, description }` from `/lua-new`. lua-cli is a TypeScri - `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/primitives.md` — the exact constructor shapes, import rules, file conventions and gotchas (all verified against lua-cli 3.33.0 source) - `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/workflows.md` — when `type = workflow` - `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/web-apps.md` — when `type = webapp` (read all of it: the route contract, the page CSP and the live-data rule decide what you may write and run) +- `${CLAUDE_PLUGIN_ROOT}/lib/knowledge/decisions.md` — when `type = decision` (§2 the three builders and their limits, §5 the options, §6 the `LuaDecision` shape and the compiler's rules) - `lua.skill.yaml` (project root; CLI-managed — never edit its primitive arrays) and `src/index.ts` (the `LuaAgent` config you must register the new primitive in) If the project has `examples/` (from `lua init --with-examples`), mirror the matching example's file layout and naming only — **never copy its platform API calls**: the 3.33.0 examples do not type-check against the shipped typings (`tsc --strict`: 23 errors in 10 files — `Channels.email.send({ body })` → the field is `text`; `Integrations.passthrough({ body })` / `res.body` → both are `data`; a non-existent `Payments`; `Orders.list` does not exist and `Orders` is not imported; `job.jobId` → `job.id`; unchecked `null` from `User.get()`; relative imports into lua-cli's own `dist/` — workflows.md §1). Take every shape from primitives.md / workflows.md or `node_modules/lua-cli/dist/api-exports.d.ts`. @@ -26,6 +27,7 @@ If the project has `examples/` (from `lua init --with-examples`), mirror the mat - mcp → `src/mcp/.ts` (`new LuaMCPServer({ transport: 'streamable-http', url, headers: () => ({...}) })`) - device → `src/devices/.ts` (`defineDevice`) · device-trigger → `src/devices/.trigger.ts` (`defineDeviceTrigger`) - voice → `src/voices/.ts` (`defineVoice`) + - decision → `src/decisions/.ts` (`export const = new LuaDecision({ name, description, questions: { … }, … })`, ⏳ lua-cli 3.48.0). Every question is a literal `Decisions.odds('…')`, `Decisions.choice('…', { key: 'description', … })` (2–64 keys) or `Decisions.score('…', ['label', …] | [{ label, description }])` (2–10 levels) — the compiler reads them from the source, so no helper functions, no spread, no computed keys. Instructions ≤ 4,000 chars; names and option keys ≤ 64 chars. Leave `provider`/`model` out unless the description asks for a specific model (then `model: ''` — a `vendor/model` id runs on OpenRouter; `provider: 'openrouter'` without `model`, or a `typesafe/…` / `openai/…` id with it, fails the compile). Set `minConfidence` only when the description names a threshold. - workflow → `src/workflows/.ts` (`export const = createWorkflow({ … }).then(…).commit()`, config as an inline object literal, every `createStep` placed). ⏳ lua-cli 3.36.0 or later (the plugin pins 3.37.0 — check the installed `lua --version`): an `agentStep` may carry `taskClass` (`classify | extract | transform | draft | research | reason | code | judge`), `model: 'class/fast' | 'class/balanced' | 'class/strong'` (or an approved code), `requires: ['structured' | 'vision' | 'largeContext' | 'codeExecution']` (`structured` whenever there is an `outputSchema`), `modelReason` (≤ 160 chars) and `effort: 'low' | 'medium' | 'high'`. Rules (workflows.md §2): a `taskClass` **must** come with a `model` on a pushed definition (`task-class-without-model` — refused at push by the server, invisible to `lua compile`); a misspelled class / task class / trait / effort is refused at push too (`model-class-unknown` etc., before any POST); `effort` is recorded and never applied unless the user later pushes with `lua push workflow --apply-effort` — say so in the report; the offline `lua test workflow` ignores all of them. On an older CLI the typings lack these members and `tsc` rejects them — leave them out. Independently of the CLI version: a step with `tier: 'job'` (or any `workspace`) should always name its own `model` — a Job step falls back to the platform's Job default, then the organization's, never the agent's, and every model reply of the attempt is billed at that model's multiplier (workflows.md §4). Say in the report which model each Job step pins and why. - webapp → **never hand-write the scaffold**: run `lua apps new ` (lua-cli ≥ 3.42.0; check `lua --version`, below it stop and report `/lua-update`). It writes `src/apps//app.ts` + `web/`, registers the app in `webApps` and excludes `src/apps/*/web` from `tsconfig.json`; when it prints `⚠️ … add:` lines instead (no `LuaAgent` found, a non-array `webApps`, a tsconfig with comments), make those edits yourself. Then, in this order (web-apps.md §2): 1. `npm --prefix src/apps//web install --ignore-scripts` @@ -34,7 +36,7 @@ If the project has `examples/` (from `lua init --with-examples`), mirror the mat 4. Write the pages in `web/src/` with `@lua-ai-global/ui` components (`@lua-ai-global/ui/`), the theme tokens (`bg-background`, `text-foreground`, `text-muted-foreground`), `lua.api(method, path, body?)` for every call and `LuaApiError` for failures. Keep `void lua.start()` and the theme lines in `main.tsx`. No CDN `