@aibridge/cli 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # aibridge
5
5
 
6
- **Let your coding agent drive the other AIs on your machine.** Cross-provider agent-to-agent delegation — plan, implement, review, red-team, and generate images across Grok, Gemini, Codex & Claude through the CLIs you already have. No API keys.
6
+ **Let your coding agent use the other AI CLIs on your machine.** Plan, implement, review, red-team, and generate images with Grok, Gemini, Codex, and Claude. No API keys.
7
7
 
8
8
  [![skills.sh](https://skills.sh/b/ycmjason/aibridge)](https://skills.sh/ycmjason/aibridge)
9
9
  [![npm](https://img.shields.io/npm/v/%40aibridge%2Fcli)](https://www.npmjs.com/package/@aibridge/cli)
@@ -15,38 +15,45 @@
15
15
 
16
16
  ---
17
17
 
18
- Your agent is one model, from one provider. Your machine probably has several more sitting behind CLIs you already use `grok`, `agy` (Antigravity), `codex`, `claude`. **aibridge** turns them into seats your agent can drive: a planner that studies your repo, an implementer that edits it and runs your real tests, a reviewer from a *different* model family that cross-checks the diff against the plan, concurrent one-shot delegates — and capabilities your agent's own provider may not offer at all, like real image generation (Codex, Antigravity, or Grok seats).
18
+ Your coding agent uses one model. Your machine may already have others available
19
+ through `grok`, `agy` (Antigravity), `codex`, or `claude`. **aibridge** lets your
20
+ agent use those models as planners, implementers, reviewers, one-shot delegates,
21
+ and image generators. Each model runs through its existing CLI login.
19
22
 
20
23
  ## Install
21
24
 
22
- One step — install the skill into your agent(s):
25
+ Install the skill into your agent:
23
26
 
24
27
  ```bash
25
28
  npx skills add ycmjason/aibridge
26
29
  ```
27
30
 
28
- That's it. The skill runs the CLI on demand via `npx -y @aibridge/cli` — nothing else to install. Ask your agent to "use aibridge", or try it yourself:
31
+ The installed skill is a small evergreen loader. It asks the latest CLI package
32
+ for canonical instructions, then pins that exact version for the rest of the
33
+ session. Routing guidance and executable behavior therefore update together.
34
+ Ask your agent to "use aibridge", or run a command directly:
29
35
 
30
36
  ```bash
31
37
  npx -y @aibridge/cli subagent --model xai-grok/grok-4.6 "summarize the architecture of this repo"
32
38
  ```
33
39
 
34
- <sup>Want the `aibridge` command on your PATH for manual use? `npm i -g @aibridge/cli` (optional).</sup>
40
+ <sup>Optional: install `aibridge` on your PATH with `npm i -g @aibridge/cli`.</sup>
35
41
 
36
42
  ## Commands
37
43
 
38
44
  | Command | Use when |
39
45
  |---|---|
40
- | `aibridge plan --model xai-grok/grok-4.6 --out plan.md "<task>"` | You want a delegate model to study the repo and expand a task into a detailed, reviewable **plan file** before any code is written |
41
- | `aibridge implement --model google-antigravity/gemini-3.7-flash <plan.md>` | You have an approved plan file and want it executed in place — with your project's **real typecheck and tests** run until green |
42
- | `aibridge review --model xai-grok/grok-4.6 --out review.md [--plan <plan.md>]` | You want a **different model** to pressure-test a diff against the plan contract, where over-reach is a finding. `--base <ref>` reviews any commit range, not just the working tree. On a clean tree it reviews the plan itself |
43
- | `aibridge subagent --model xai-grok/grok-4.6 "<task>"` | A self-contained task deserves a concurrent delegate, a cross-model second opinion, or a red-team pass |
44
- | `aibridge image-gen --model openai-codex/gpt-5.6-sol --out out.png "<prompt>"` | You need a real raster image — on a Codex, Antigravity, or Grok seat, with render verification |
45
- | `aibridge models [--json]` | You need the exact facts for every registered model seat (accepted efforts, image format, pinned model ID) |
46
- | `aibridge quota` | Two-second check of every backend's remaining quota before you pipeline work |
47
- | `aibridge runs` | Inspect or watch past delegation runs (`~/.aibridge/runs`) |
48
-
49
- The three verbs compose into an orchestrator-driven loop your agent stays in charge of:
46
+ | `aibridge plan --model xai-grok/grok-4.6 --out plan.md "<task>"` | Study the repo and write a detailed plan file |
47
+ | `aibridge implement --model google-antigravity/gemini-3.7-flash <plan.md>` | Execute an approved plan and run the project's checks |
48
+ | `aibridge review --model xai-grok/grok-4.6 --out review.md [--plan <plan.md>] [--base <ref>]` | Review a diff or, on a clean tree, a plan |
49
+ | `aibridge subagent --model xai-grok/grok-4.6 "<task>"` | Delegate a self-contained task or request a second opinion |
50
+ | `aibridge image-gen --model openai-codex/gpt-5.6-sol --out out.png "<prompt>"` | Generate and verify a raster image |
51
+ | `aibridge models [--json]` | List registered models and their capabilities |
52
+ | `aibridge quota` | Show quota remaining for every backend |
53
+ | `aibridge runs` | Inspect or watch run logs in `~/.aibridge/runs` |
54
+ | `aibridge skill [topic]` | Print the canonical agent instructions bundled with this CLI version |
55
+
56
+ Use `plan`, `implement`, and `review` as one controlled workflow:
50
57
 
51
58
  ```
52
59
  aibridge plan --model xai-grok/grok-4.6 --out plan.md "add rate limiting to the API" # delegate writes plan.md
@@ -55,21 +62,26 @@ aibridge implement --model google-antigravity/gemini-3.7-flash plan.md
55
62
  aibridge review --model xai-grok/grok-4.6 --out review.md --plan plan.md # a third seat cross-checks the diff
56
63
  ```
57
64
 
58
- Plan files not their contents — travel between stages, so the loop is nearly free on your agent's context.
65
+ Only the plan path passes between stages, which keeps the plan out of the
66
+ orchestrator's conversation context.
59
67
 
60
68
  ## How it works
61
69
 
62
- - **The skill carries judgment; the CLI owns execution.** The skill teaches your agent prompt-craft, seat selection, and when to gate; the CLI deterministically drives the backing CLIs, captures their output, verifies results (a "generated image" under 100 KB is a code-drawn fake, an empty answer is a quota death), and logs every run.
63
- - **Seats stay cross-model by default.** Grok plans and reviews, Gemini implements — a model never reviews its own diff, and independent eyes catch what shared blind spots miss.
64
- - **No API keys.** Delegation runs on the backing CLIs' existing logins, each spending its own quota. (The skill treats a backend that shares your agent's own quota pool as a last resort.)
65
- - **Models are canonical slugs**: `<vendor>-<cli>/<model>[-<effort>]` e.g. `xai-grok/grok-4.6`, `google-antigravity/gemini-3.7-flash`, `openai-codex/gpt-5.6-sol-high`, `anthropic-claude/opus-5`. No aliases — not short ones, and not moving vendor aliases like `opus`: every seat pins an exact model version. `aibridge <command> --help` lists every seat.
70
+ - **One package owns instructions and execution.** The installed skill only
71
+ bootstraps the latest package. That package supplies routing guidance, starts
72
+ the backend, validates known failure modes, and logs the run.
73
+ - **Review stays cross-model.** The recommended workflow uses Grok to plan and
74
+ review, and Gemini to implement.
75
+ - **Existing logins, no API keys.** Each backend uses its CLI login and quota.
76
+ - **Every model has a canonical slug:**
77
+ `<vendor>-<cli>/<model>[-<effort>]`, such as `xai-grok/grok-4.6` or
78
+ `openai-codex/gpt-5.6-sol-high`. There are no aliases. Run
79
+ `aibridge <command> --help` for the current list.
66
80
 
67
81
  ## Tell your agent when to reach for it
68
82
 
69
- aibridge doesn't decide when to delegate your agent does, and left alone it will
70
- mostly keep the work for itself. Put the routing rule in whatever instructions file
71
- your agent already reads at the start of every session (`AGENTS.md`, `CLAUDE.md`,
72
- `.cursorrules`, …). Something like:
83
+ aibridge does not decide when to delegate. Put a routing rule in the instructions
84
+ file your agent reads (`AGENTS.md`, `CLAUDE.md`, `.cursorrules`, and so on):
73
85
 
74
86
  ```markdown
75
87
  ## Delegation gate — decide before you implement
@@ -91,21 +103,32 @@ Delegated work is yours to verify: re-run the real gates before trusting a diff.
91
103
  Prefer a reviewer from a different model family than whoever implemented.
92
104
  ```
93
105
 
94
- Tune the seats and thresholds to your own quotas. The value is that the decision is
95
- explicit and made *before* the work starts, rather than rationalised afterwards.
106
+ Adjust the models and thresholds for your quotas. Make the routing decision before
107
+ implementation starts.
96
108
 
97
109
  ## Requirements
98
110
 
99
111
  - **Node ≥ 24.11**
100
- - The backing CLIs you want to use, on `PATH` and authed: [`grok`](https://github.com/superagent-ai/grok-cli), `agy` (Antigravity), [`codex`](https://github.com/openai/codex), [`claude`](https://claude.com/claude-code) — any subset works; commands fail fast with install hints for missing ones.
112
+ - At least one authenticated backend CLI on `PATH`:
113
+ [`grok`](https://github.com/superagent-ai/grok-cli), `agy` (Antigravity),
114
+ [`codex`](https://github.com/openai/codex), or
115
+ [`claude`](https://claude.com/claude-code). Missing CLIs produce install hints.
101
116
 
102
117
  ## Packages
103
118
 
104
- Everything is published under the [`@aibridge`](https://www.npmjs.com/org/aibridge) scope: [`@aibridge/cli`](https://www.npmjs.com/package/@aibridge/cli) (the command), `@aibridge/proc` (spawn/capture), and one driver per backing CLI — `@aibridge/driver-agy`, `@aibridge/driver-grok`, `@aibridge/driver-codex`, `@aibridge/driver-claude` — reusable if you want to drive a single CLI from your own code.
119
+ Packages use the [`@aibridge`](https://www.npmjs.com/org/aibridge) scope:
120
+ [`@aibridge/cli`](https://www.npmjs.com/package/@aibridge/cli),
121
+ `@aibridge/proc`, and one reusable driver for each backend:
122
+ `driver-agy`, `driver-grok`, `driver-codex`, and `driver-claude`.
105
123
 
106
124
  ## Security
107
125
 
108
- aibridge executes real delegation that's the product, and security scanners rightly notice: backing CLIs read/write files and run shell in tools mode, **at the same trust level as the agent you already run**. Nothing gains more access than you granted your agent and those CLIs when you installed them. Task content goes to the delegate's provider (use `--no-tools` for untrusted input — reasoning only, no file/shell access). All packages publish from this public repo via OIDC with [SLSA provenance](https://www.npmjs.com/package/@aibridge/cli), with no install-time scripts.
126
+ In tools mode, delegates can read files, write files, and run shell commands with
127
+ the same access as the invoking agent. Task content is sent to the selected
128
+ provider. Use `--no-tools` for untrusted input. Packages are published from this
129
+ public repository through OIDC with
130
+ [SLSA provenance](https://www.npmjs.com/package/@aibridge/cli) and no install-time
131
+ scripts.
109
132
 
110
133
  ## Contributing & development
111
134
 
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as runCli, t as buildContext } from "./context-BQgclUqy.mjs";
2
+ import { r as runCli, t as buildContext } from "./context-DeJmEXLe.mjs";
3
3
  //#region src/cli.ts
4
4
  await runCli(buildContext(process), process.argv.slice(2));
5
5
  //#endregion
@@ -1656,6 +1656,62 @@ const runs = buildCommand({
1656
1656
  fullDescription: fullDescription$1
1657
1657
  }
1658
1658
  });
1659
+ const PACKAGE_VERSION = createRequire(import.meta.url)("../package.json").version;
1660
+ //#endregion
1661
+ //#region src/commands/skill/impl.ts
1662
+ const TOPICS = {
1663
+ plan: "reference/plan.md",
1664
+ implement: "reference/implement.md",
1665
+ review: "reference/review.md",
1666
+ subagent: "reference/subagent.md",
1667
+ "image-gen": "reference/image-gen.md",
1668
+ why: "reference/why.md"
1669
+ };
1670
+ function instructionPath(relativePath) {
1671
+ const found = [new URL(`../instructions/${relativePath}`, import.meta.url), new URL(`../../../instructions/${relativePath}`, import.meta.url)].find((candidate) => existsSync(candidate));
1672
+ if (!found) throw new Error(`bundled instruction file is missing: ${relativePath}`);
1673
+ return found;
1674
+ }
1675
+ function readInstruction(relativePath) {
1676
+ return readFileSync(instructionPath(relativePath), "utf8").trimEnd();
1677
+ }
1678
+ function skillImpl(topic) {
1679
+ if (topic !== void 0 && !(topic in TOPICS)) {
1680
+ this.process.stderr.write(`aibridge skill: unknown topic ${JSON.stringify(topic)}; expected one of: ${Object.keys(TOPICS).join(", ")}\n`);
1681
+ this.process.exitCode = 2;
1682
+ return;
1683
+ }
1684
+ try {
1685
+ const sections = [`Command runner for these instructions: \`${`npx -y @aibridge/cli@${PACKAGE_VERSION}`}\`\nUse that exact prefix for every aibridge command below; do not substitute a global binary.`, readInstruction("SKILL.md")];
1686
+ if (topic !== void 0) sections.push(readInstruction(TOPICS[topic]));
1687
+ this.process.stdout.write(`${sections.join("\n\n---\n\n")}\n`);
1688
+ } catch (error) {
1689
+ const message = error instanceof Error ? error.message : String(error);
1690
+ this.process.stderr.write(`aibridge skill: ${message}\n`);
1691
+ this.process.exitCode = 1;
1692
+ }
1693
+ }
1694
+ //#endregion
1695
+ //#region src/commands/skill/command.ts
1696
+ function skillCommand(_flags, topic) {
1697
+ skillImpl.call(this, topic);
1698
+ }
1699
+ const skill = buildCommand({
1700
+ func: skillCommand,
1701
+ parameters: {
1702
+ flags: {},
1703
+ positional: {
1704
+ kind: "tuple",
1705
+ parameters: [{
1706
+ brief: "Command-specific instructions to append to the router",
1707
+ parse: String,
1708
+ placeholder: "topic",
1709
+ optional: true
1710
+ }]
1711
+ }
1712
+ },
1713
+ docs: { brief: "Print the canonical agent instructions bundled with this CLI" }
1714
+ });
1659
1715
  //#endregion
1660
1716
  //#region src/commands/subagent/impl.ts
1661
1717
  async function subagent$1(flags, prompt) {
@@ -1777,9 +1833,6 @@ function normalizeExitCode(ctx) {
1777
1833
  }
1778
1834
  if (code !== 0 && code !== 1 && code !== 2 && code !== 3) ctx.process.exitCode = 1;
1779
1835
  }
1780
- //#endregion
1781
- //#region src/app.ts
1782
- const { version } = createRequire(import.meta.url)("../package.json");
1783
1836
  const app = buildApplication(buildRouteMap({
1784
1837
  routes: {
1785
1838
  plan,
@@ -1789,12 +1842,13 @@ const app = buildApplication(buildRouteMap({
1789
1842
  "image-gen": imageGen,
1790
1843
  runs,
1791
1844
  quota,
1792
- models
1845
+ models,
1846
+ skill
1793
1847
  },
1794
1848
  docs: { brief: "Bridge tasks to the other AI CLIs on this machine — a plan → implement → review workflow, task delegation, and image generation (codex / agy / grok seats)." }
1795
1849
  }), {
1796
1850
  name: "aibridge",
1797
- versionInfo: { currentVersion: version },
1851
+ versionInfo: { currentVersion: PACKAGE_VERSION },
1798
1852
  scanner: { caseStyle: "allow-kebab-for-camel" }
1799
1853
  });
1800
1854
  /** Public entry used by cli.ts and index.ts — preserves runCli(ctx, argv) surface. */
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { S as supportsImageGen, _ as backendModelId, a as readRunLogs, b as listModelHelpLines, c as evaluateAgyPreflight, d as preflightModel, f as renderPreflightRefusal, g as MODELS, h as positiveIntSeconds, i as listRuns, l as evaluateCodexPreflight, m as nonEmptyPrompt, n as app, o as startRun, p as getDriver, r as runCli, s as delegate, t as buildContext, u as preflightCodex, v as formatImageGenModelError, x as resolveModel, y as formatUnknownModelError } from "./context-BQgclUqy.mjs";
1
+ import { S as supportsImageGen, _ as backendModelId, a as readRunLogs, b as listModelHelpLines, c as evaluateAgyPreflight, d as preflightModel, f as renderPreflightRefusal, g as MODELS, h as positiveIntSeconds, i as listRuns, l as evaluateCodexPreflight, m as nonEmptyPrompt, n as app, o as startRun, p as getDriver, r as runCli, s as delegate, t as buildContext, u as preflightCodex, v as formatImageGenModelError, x as resolveModel, y as formatUnknownModelError } from "./context-DeJmEXLe.mjs";
2
2
  export { MODELS, app, backendModelId, buildContext, delegate, evaluateAgyPreflight, evaluateCodexPreflight, formatImageGenModelError, formatUnknownModelError, getDriver, listModelHelpLines, listRuns, nonEmptyPrompt, positiveIntSeconds, preflightCodex, preflightModel, readRunLogs, renderPreflightRefusal, resolveModel, runCli, startRun, supportsImageGen };
@@ -0,0 +1,115 @@
1
+ # aibridge
2
+
3
+ Use other providers' authenticated AI CLIs as delegates. You choose the task,
4
+ model, and prompt; aibridge runs the backend and validates its output. Each run
5
+ spends the selected backend's quota.
6
+
7
+ Load the `why` topic only when a rule appears unsuitable.
8
+
9
+ ## Running it
10
+
11
+ The output header defines the exact command runner for this instruction set.
12
+ Examples below abbreviate that runner as `aibridge`; always substitute the exact
13
+ runner. This keeps instructions and executable behavior on the same version.
14
+
15
+ Requires Node 24.11 or later. If Node is older, ask the user to upgrade with
16
+ `nvm install 24` or `mise use node@24`. Ask before any global install.
17
+
18
+ Backing CLIs must be on `PATH` and authed: `grok`, `agy` (Antigravity), `codex`,
19
+ `claude`. Any subset works; commands fail fast with install hints.
20
+
21
+ ## Where `--out` goes
22
+
23
+ - Put permanent project assets in their final location, such as
24
+ `--out public/icons/settings.png`.
25
+ - Put plans, reviews, and drafts in `<repo root>/.aibridge/`. Outside a
26
+ repository, use `.aibridge/` under the current directory.
27
+ - Name files by topic. Promote a draft to its real path once it is the keeper.
28
+ - Once per session, before the first write: `git check-ignore -q .aibridge/`
29
+ Keep the trailing slash so a directory-only rule matches before the directory
30
+ exists. If the command fails, ask to add `.aibridge/` to `.gitignore`.
31
+ - An explicit path from the user wins over all of this.
32
+
33
+ ## Subcommands
34
+
35
+ | Command | Description |
36
+ |---|---|
37
+ | `plan` | Expand a task into a detailed implementation plan file |
38
+ | `implement` | Implement a plan file in place and run the real checks |
39
+ | `review` | Review a diff, commit range, or plan contract |
40
+ | `subagent` | Delegate a self-contained task to another model |
41
+ | `image-gen` | Generate a raster image with a Codex, Antigravity, or Grok seat |
42
+ | `runs` | Monitor and inspect execution runs |
43
+ | `quota` | Show backend quota and reset times |
44
+ | `models` | List registered model seats and capabilities |
45
+
46
+ `plan`, `review` and `image-gen` require `--out` and print only a verdict/path
47
+ line. `subagent` and `implement` have no `--out`; they print the delegate's
48
+ answer to stdout, and `subagent --out foo.md` exits 2 with
49
+ `No flag registered for --out`. Redirect if you want that answer in a file.
50
+
51
+ ## Routing
52
+
53
+ 1. **First word is a subcommand** → use the command-specific section appended
54
+ to this output. If it is missing, run `aibridge skill <subcommand>` before
55
+ taking action.
56
+ 2. **No subcommand** → infer:
57
+ - an image, icon or graphic to make → `image-gen`;
58
+ - a self-contained task, cross-model second opinion, or red-team → `subagent`;
59
+ - sizeable or risky implementation work → `plan` → *you read, edit and
60
+ approve the plan file* → `implement` → `review --plan <file>`. For
61
+ high-risk designs only, add a gate before any code is written:
62
+ `review --plan` on a clean tree.
63
+
64
+ If genuinely ambiguous, show the table above and ask.
65
+ 3. **Unsure of the current flags?** Run `aibridge <command> --help`.
66
+
67
+ ## Model seats
68
+
69
+ `--model` is required on every command that spends a delegate (`plan`,
70
+ `implement`, `review`, `subagent`, `image-gen`); nothing is chosen for you.
71
+ `quota`, `models` and `runs` take no `--model`. Starting points, not
72
+ benchmarks:
73
+
74
+ | slug | plan | implement | review | image-gen |
75
+ |---|---|---|---|---|
76
+ | `xai-grok/grok-4.6` | ✅ small–mid, well-scoped | ○ | ✅ | ○ JPEG |
77
+ | `xai-grok/grok-4.5` | ○ | ✅ any fidelity | ○ | ○ JPEG |
78
+ | `openai-codex/gpt-5.6-sol` | ✅ mid–big, ambiguous | ○ | ✅ | ✅ PNG |
79
+ | `anthropic-claude/opus-5` | ✅ mid–big, ambiguous | ○ | ✅ | ✗ |
80
+ | `google-antigravity/gemini-3.7-flash` | ○ | ✅ needs high–xhigh detail | ○ | ○ JPEG |
81
+ | `anthropic-claude/sonnet-5` | ○ | ✅ needs high detail | ○ | ✗ |
82
+
83
+ ✅ recommended · ○ supported · ✗ unsupported. For `plan`, the qualifier describes
84
+ how much ambiguity the model can resolve. For `implement`, it describes how
85
+ detailed the plan must be.
86
+ **If the task fits no row, or the user has said how they want work routed, ask
87
+ rather than guess.**
88
+
89
+ Also registered: `openai-codex/gpt-5.6-terra` / `-luna` (cheaper coding tiers),
90
+ `anthropic-claude/fable-5` (hardest, longest-running work),
91
+ `anthropic-claude/haiku-4-5` (quick answers),
92
+ `google-antigravity/gemini-3.6-flash`, `google-antigravity/gemini-3.1-pro`
93
+ (`-high`/`-low` only), and agy's `claude-sonnet-4-6` /
94
+ `claude-opus-4-6-thinking` / `gpt-oss-120b-medium`. Run `aibridge models
95
+ [--json]` for exact per-seat facts, or `aibridge <command> --help` for the list.
96
+
97
+ - **One grok stage at a time.** ~30 req/min, ~1k msgs/day, and both tiers share
98
+ that budget.
99
+ - **`grok-4.6` plans and reviews, `grok-4.5` implements.** They are different
100
+ seats, not old and new.
101
+ - **The reviewer must be a different model family from whoever implemented**,
102
+ including when that was you.
103
+ - **A backend that shares YOUR quota is a last resort**: `anthropic-claude/*`
104
+ for Claude-based agents, `google-antigravity/*` for Antigravity-based agents.
105
+ Say so when you reach for it.
106
+ - **Swap on quota**: `openai-codex/gpt-5.6-sol[-<effort>]` is the usual alternate.
107
+ - Preflight runs before every delegation. `aibridge quota` is the manual check
108
+ before you pipeline several stages.
109
+
110
+ ## Trust
111
+
112
+ In tools mode, delegates can read files, write files, and run shell commands at
113
+ your trust level. The selected provider receives the prompt and any content the
114
+ delegate reads. Use `--no-tools` for untrusted input; it disables file and shell
115
+ access.
@@ -0,0 +1,107 @@
1
+ # image-gen — generate an image via a model seat
2
+
3
+ Part A covers the command. Part B covers prompt design, which applies even when
4
+ you only need to return a prompt.
5
+
6
+ ## A. Calling it
7
+
8
+ ```bash
9
+ aibridge image-gen --model <slug> --out <file.png> "<full prompt — see part B>" \
10
+ [--aspect-ratio 16:9] [--image ref.png] [--transparent] \
11
+ [--timeout 600] [--no-preflight] [--json]
12
+ ```
13
+
14
+ | slug | renders via | format |
15
+ |---|---|---|
16
+ | `openai-codex/gpt-5.6-sol` (recommended) | Codex CLI | PNG |
17
+ | `google-antigravity/gemini-3.7-flash` | Antigravity CLI (`agy`) | JPEG |
18
+ | `xai-grok/grok-4.6` | `api.x.ai` directly, on `~/.grok/auth.json` | JPEG |
19
+
20
+ Other seats fail fast with a list of capable models. The grok seat renders
21
+ without `grok` on `PATH`; the CLI is spawned only to refresh the token, before a
22
+ request when `expires_at` is close and again as a backstop if one comes back
23
+ 401. `grok login` is still what sets the seat up.
24
+
25
+ - `--out` is required and its extension must match the seat's format above
26
+ (`.png` for any `--transparent` run). A mismatch is rejected before anything
27
+ runs. The file holds the model's own bytes verbatim, except on a
28
+ chroma-keyed `--transparent` run, which writes the locally keyed PNG.
29
+ - **Render into the asset's real home** (`public/icons/settings.png`) when the
30
+ project keeps it. Drafts go to `.aibridge/`; see [SKILL.md](../SKILL.md).
31
+ - `--aspect-ratio N:M` sets geometry. Exact pixels are whatever the model
32
+ renders; resize downstream.
33
+ - `--image a.png,b.png` attaches references and routes to the seat's edit path.
34
+ - `--json` prints `{ out, bytes, width, height, aspectRatio, model, backend, transparency, real }`.
35
+ - Preflight is on by default: an exhausted seat exits 3 and names the
36
+ alternatives instead of spending a paid render. Argument checks run first, so
37
+ bad flags still cost no network call.
38
+
39
+ ### Transparency
40
+
41
+ - `--transparent` works on every image seat and always writes PNG. Codex gives
42
+ native alpha; grok and gemini are chroma-keyed with binary edges. Fine for
43
+ flat icons, logos and stickers; not for hair, smoke or glass.
44
+ - **Say nothing about the background in the prompt when using it.** The CLI
45
+ writes the backdrop instruction per seat, and a colour of your own overrides
46
+ it: the key then finds nothing and the paid render comes back opaque. Writing
47
+ "transparent background" into the prompt without the flag is refused on
48
+ chroma seats.
49
+ - **A green subject is keyed away with the backdrop** on chroma seats. Anything
50
+ that must be green needs `openai-codex/*`.
51
+ - Both surfaces report the path taken: the result line says
52
+ `transparency: native` / `chroma-keyed`, `--json` carries
53
+ `"native" | "chroma" | null`. Quote it when the edges matter. Keying under 2%
54
+ of the image warns: the model likely ignored the backdrop instruction.
55
+
56
+ ### Reference images
57
+
58
+ ```bash
59
+ aibridge image-gen --model openai-codex/gpt-5.6-sol \
60
+ "the same woman, now in a denim shirt in a bright kitchen, waist-up" \
61
+ --out avatar2.png --image avatar.png --aspect-ratio 9:16
62
+ ```
63
+
64
+ With a reference, write the prompt as a **diff**: say only what changes. The
65
+ reference carries identity, framing and style.
66
+
67
+ ## B. Writing the prompt
68
+
69
+ 1. **Never state the image's purpose** (no "app icon", "hero banner"). Describe
70
+ how it looks, not its job.
71
+ 2. **Give the aspect ratio** via `--aspect-ratio` and/or the prompt text.
72
+ 3. **Always specify the background**: a hex colour, or `opaque`/`auto`. Except
73
+ on a `--transparent` run, where you say nothing about it.
74
+ 4. **Specify** subject, composition, palette, style/medium, mood, lighting.
75
+ 5. **Lock the critical, free the rest.** Lock verbatim text in straight quotes,
76
+ brand hex, required layout, the hero subject, and every "no X". Over-specified
77
+ incidental detail flattens the result.
78
+
79
+ ### Worked example
80
+
81
+ > `Square 1:1 aspect ratio. Solid warm cream #F7F1EA background. A single flat-design
82
+ > fanned stack of three rounded-corner cards in coral orange #FF5A1F, centered,
83
+ > ~55% of the frame, soft drop shadow. Calm, minimal, modern. No text, no border,
84
+ > no gradient.`
85
+
86
+ Locked: ratio, background hex, subject, brand orange, the no-text/border/gradient
87
+ constraints. Free: fan angle, shadow softness, spacing. On a `--transparent` run,
88
+ drop the background sentence and the drop shadow: a soft shadow has no flat
89
+ backdrop colour to key against and survives as a pale halo.
90
+
91
+ ### Edits and retries
92
+
93
+ 1. **Describe the desired result.** State what the finished image contains,
94
+ rather than only what to remove or correct.
95
+ 2. **Name the visual criterion first.** Phrases such as "the near plane" or
96
+ "everyone waiting" often work better than an object inventory. Enumerate
97
+ objects only if the criterion fails.
98
+ 3. **Rewrite failed prompts; do not append to them.** Simplify the request. For
99
+ a near-correct render, make the next instruction as short as possible.
100
+ 4. **Change strategy after the same failure occurs twice.** Try a different
101
+ reference, composition, or fresh generation instead of another rewording.
102
+ 5. **Retry from the original reference.** Chaining generated outputs causes
103
+ unrequested details to drift.
104
+ 6. **Check your terminology.** A near-miss word can produce a coherent image of
105
+ the wrong concept.
106
+ 7. **Verify unchanged details in context.** Inspect the asset in its final
107
+ placement and, when relevant, in motion.
@@ -0,0 +1,51 @@
1
+ # implement — execute a plan file
2
+
3
+ An implementer edits the working tree and runs the project's checks. This is the
4
+ third step in **`plan` → read and approve → `implement` → `review`**.
5
+
6
+ Run this only after reading and approving the plan. If the implementer would
7
+ need to make a product or architecture decision, fix the plan first.
8
+
9
+ ## Usage
10
+
11
+ ```bash
12
+ aibridge implement --model <slug> <plan-file>
13
+ --model <slug> implementer model (required, e.g. google-antigravity/gemini-3.7-flash)
14
+ --timeout <secs> max seconds (default: 1800)
15
+ --no-preflight skip the quota preflight
16
+ ```
17
+
18
+ ## Behaviour
19
+
20
+ The delegate runs with full tools at the repository root. It must follow the
21
+ plan, edit only named files, run the specified checks until they pass, and avoid
22
+ commits, pushes, and unrelated deletions.
23
+
24
+ ## Output
25
+
26
+ ```
27
+ <delegate's short summary>
28
+
29
+ <git diff --stat>
30
+ untracked files: <count>
31
+ run: <run id>
32
+ ```
33
+
34
+ Exit 0: completed with tree changes. Exit 1: delegate failed, timed out, gave no
35
+ usable answer, or changed nothing (a no-op implement is a failure). Exit 2: bad
36
+ args or missing plan file. Exit 3: quota preflight refusal.
37
+
38
+ ## After it returns
39
+
40
+ 1. **Re-run the checks yourself.** The summary reports the delegate's claim.
41
+ 2. Then `aibridge review --model xai-grok/grok-4.6 --plan <plan-file> --out .aibridge/review.md`.
42
+
43
+ ## Gotchas
44
+
45
+ - Keep the implementer a different model family from the reviewer. The
46
+ recommended seats (gemini implements, grok reviews) comply; if you override
47
+ one, check the other.
48
+ - agy quota is shared by model group. Two concurrent agy-heavy runs drain
49
+ the same window. Run `aibridge quota` before pipelining.
50
+ - The timeout covers the whole run including gate-fixing loops. Raise it for big
51
+ plans rather than letting a near-done run get killed.
@@ -0,0 +1,69 @@
1
+ # plan — write a detailed implementation plan file
2
+
3
+ A planner studies the codebase and writes a detailed plan to a file. This is the
4
+ first step in **`plan` → read and approve → `implement` → `review`**. Pass the
5
+ file path—not its contents—between stages.
6
+
7
+ Use it for sizeable or risky work. For small, fully-specified chunks use
8
+ `subagent`, or just do them.
9
+
10
+ ## Usage
11
+
12
+ ```bash
13
+ aibridge plan --model <slug> --out <file> "<task prompt>"
14
+ --model <slug> planner model (required, e.g. xai-grok/grok-4.6)
15
+ --out <file> where to write the plan (required)
16
+ --timeout <secs> max seconds (default: 1800)
17
+ --no-preflight skip the quota preflight
18
+ ```
19
+
20
+ The positional argument is the task prompt, not a file path.
21
+
22
+ ## Writing the task prompt
23
+
24
+ The planner can read the code. Do not paste file contents. Provide only what it
25
+ cannot infer:
26
+
27
+ - the goal and the user-visible behaviour change;
28
+ - hard constraints (APIs to keep stable, zero-dep rules, style conventions);
29
+ - scope boundaries and non-goals;
30
+ - architectural calls you have already made, since the planner details your
31
+ design rather than overruling it;
32
+ - starting files, if the repo is large.
33
+
34
+ ## Behaviour
35
+
36
+ - The planner writes exactly one file (`--out`). Any other change to the working
37
+ tree fails the run (exit 1, paths listed). An `--out` inside the repo is
38
+ exempt.
39
+ - The plan must end with `## Open questions` (`None.` when confident). The count
40
+ prints on stdout.
41
+
42
+ ## Output
43
+
44
+ ```
45
+ plan: /abs/path/to/plan.md
46
+ open questions: 2
47
+ run: <run id>
48
+ ```
49
+
50
+ Exit 0 even with open questions. Exit 1: plan missing, empty, no open-questions
51
+ section, tree dirtied, delegate failure or timeout. Exit 2: bad arguments.
52
+ Exit 3: quota preflight refusal.
53
+
54
+ ## After it returns
55
+
56
+ 1. **Read the plan file.** It is the implementation contract.
57
+ 2. Resolve every open question: edit the file directly, or re-run `plan` with a
58
+ sharpened prompt.
59
+ 3. High-risk design? Gate it first:
60
+ `aibridge review --model xai-grok/grok-4.6 --plan <file> --out .aibridge/review.md`
61
+ on a clean tree.
62
+ 4. Then `aibridge implement --model google-antigravity/gemini-3.7-flash <file>`.
63
+
64
+ ## Gotchas
65
+
66
+ - `--out` belongs in `.aibridge/` (see [SKILL.md](../SKILL.md)); check it is
67
+ gitignored once per session.
68
+ - grok is capped at ~30 req/min, ~1k msgs/day, one run at a time. Never run two
69
+ grok stages concurrently.
@@ -0,0 +1,75 @@
1
+ # review — cross-model review of a diff or a plan
2
+
3
+ A reviewer inspects a diff, optionally against a plan contract, and writes its
4
+ report to a file. Standard output contains only the verdict and paths.
5
+
6
+ ## Usage
7
+
8
+ ```bash
9
+ aibridge review --model <slug> --out <file> [options]
10
+ --model <slug> reviewer model (required, e.g. xai-grok/grok-4.6)
11
+ --plan <file> plan contract; over-reach against it is a finding
12
+ --base <ref> any git ref or range to diff against (default: HEAD)
13
+ --out <file> full report destination (required)
14
+ --timeout <secs> max seconds (default: 1200)
15
+ --no-preflight skip the quota preflight
16
+ ```
17
+
18
+ ## Picking the diff
19
+
20
+ `--base` is passed straight to `git diff`, so any ref or range git accepts
21
+ works: `HEAD~3`, a branch, a SHA, a tag, `v1.2.0..HEAD`.
22
+
23
+ ```bash
24
+ # uncommitted work only (the default base, HEAD)
25
+ aibridge review --model xai-grok/grok-4.6 --out .aibridge/review.md
26
+
27
+ # the 3 commits you just made
28
+ aibridge review --model xai-grok/grok-4.6 --base HEAD~3 --out .aibridge/review.md
29
+
30
+ # the whole branch, against the plan contract
31
+ aibridge review --model xai-grok/grok-4.6 --base main \
32
+ --plan .aibridge/plan.md --out .aibridge/review.md
33
+ ```
34
+
35
+ Use `--base` to review committed work. Do not copy a diff into a file for
36
+ `subagent`. Uncommitted changes are included unless the range fixes both ends.
37
+
38
+ ## Modes (detected before any model spend)
39
+
40
+ 1. **Diff review:** changes or untracked files exist relative to `--base`. With
41
+ `--plan`, unrequested changes count as over-reach.
42
+ 2. **Plan review:** nothing differs from `--base` and `--plan` is given.
43
+ Reviews the plan for soundness, edge cases, safety, feasibility. Use it as a
44
+ pre-implementation gate on high-risk designs.
45
+ 3. **No input:** nothing differs and no `--plan` is given. Exits 2.
46
+
47
+ ## Output & exit codes
48
+
49
+ ```
50
+ PASS | FINDINGS: 1 critical, 0 major, 3 minor
51
+ review: /abs/path/to/review.md
52
+ run: <run id>
53
+ ```
54
+
55
+ - `0`: PASS, or minor-only findings.
56
+ - `1`: critical or major findings; unparseable verdict (raw answer + paths still
57
+ print); missing or empty report file; delegate failure or timeout.
58
+ - `2`: bad flags, missing plan file, nothing to review, bad base ref.
59
+ - `3`: quota preflight refusal.
60
+
61
+ ## After it returns
62
+
63
+ - `PASS` → proceed (commit, or report done).
64
+ - Findings → read the report, then judge. Over-reach findings can be scope you
65
+ added deliberately: the reviewer flags, you decide. Fix what is real, re-run.
66
+ - Never let a model review its own diff. The recommended seats (grok reviews,
67
+ gemini implements) already comply; if you override one, check the other.
68
+
69
+ ## Gotchas
70
+
71
+ - The report file is required even for PASS. Missing or empty fails the run.
72
+ - Verdict parsing accepts the line first, last, or at the end of a narration
73
+ blob (grok concatenates progress prose). If it still fails, you get exit 1
74
+ with the raw answer plus the report path on stdout.
75
+ - A bad `--base` ref is a hard error (exit 2), not a silent dirty-tree fallback.
@@ -0,0 +1,48 @@
1
+ # subagent — delegate a task to another model
2
+
3
+ Delegate one self-contained task to another provider's model. Use this for a
4
+ second opinion, red-team review, long-context analysis, or a clearly specified
5
+ piece of work.
6
+
7
+ ## Usage
8
+
9
+ ```bash
10
+ aibridge subagent --model <slug> "<self-contained prompt>" [options]
11
+ --model <slug> required, canonical slug (no short aliases)
12
+ --timeout <secs> max seconds (default: 600)
13
+ --no-tools reasoning only: no file or shell access
14
+ --no-preflight skip the quota preflight
15
+ --json machine-readable, e.g. {"model": "grok-4.6", "slug": "xai-grok/grok-4.6", ...}
16
+ ```
17
+
18
+ The answer prints to stdout. There is no `--out`; redirect if you want a file.
19
+
20
+ Effort suffixes work on seats that support them
21
+ (`xai-grok/grok-4.6-medium`, `google-antigravity/gemini-3.7-flash-low`,
22
+ `anthropic-claude/sonnet-5-max`). The seat table is in [SKILL.md](../SKILL.md);
23
+ `aibridge subagent --help` prints the live list.
24
+
25
+ **Tools are ON by default** — the delegate reads/writes files and runs shell.
26
+
27
+ ## Writing the prompt
28
+
29
+ Write for a capable model with no conversation context:
30
+
31
+ 1. **Self-contained.** Paste the code or spec to act on. Never reference "what
32
+ we discussed".
33
+ 2. **Specify the approach.** Include design decisions, interfaces, files, and
34
+ constraints without prescribing every line of code.
35
+ 3. **State the constraints.** Run the real typecheck and tests until green;
36
+ write code only, no commit/push/deploy/delete; reply with a short summary.
37
+ 4. **Verify the result.** Re-run the real gates yourself.
38
+
39
+ ## When to stay native instead
40
+
41
+ - The task needs session-specific tools, skills, or MCP servers.
42
+ - It needs conversational context or live user guidance.
43
+ - It needs strict schema validation or guaranteed retry orchestration.
44
+
45
+ ## Scaling up
46
+
47
+ For large or multi-file work, use the three verbs instead of raw subagent calls:
48
+ [plan](plan.md) → you approve → [implement](implement.md) → [review](review.md).
@@ -0,0 +1,54 @@
1
+ # why — the reasoning behind the rules
2
+
3
+ This page explains rules that the command guides state without rationale. Read
4
+ it when a rule appears unsuitable for your case.
5
+
6
+ **Paths travel between stages, not contents.** A plan re-emitted into your
7
+ context costs you the tokens the split was meant to save. `plan` writes a file,
8
+ `implement` reads that path, `review` takes it as `--plan`. Nothing round-trips
9
+ through you except your judgment.
10
+
11
+ **You read the plan file.** That sign-off is the entire point of splitting plan
12
+ from implement. Skip it and you have an unreviewed contract that a second model
13
+ will now execute literally.
14
+
15
+ **The implementer is a pure do-er.** It executes a fully-designed plan and does
16
+ not hold the surrounding vision. When a plan turns out to need that vision, the
17
+ design work upstream was insufficient. Fix the plan rather than briefing the
18
+ implementer.
19
+
20
+ **Reviewers are cross-model on purpose.** A model reviewing its own diff shares
21
+ its own blind spots and will wave through the thing it just failed to see. This
22
+ applies to you too: prefer a reviewer outside your own model family for code you
23
+ wrote yourself.
24
+
25
+ **Over-reach is a finding.** A delegate that also refactors three neighbouring
26
+ files has left the contract, and the diff you now have to verify is bigger than
27
+ the one you asked for. The reviewer flags it; you decide whether it was scope
28
+ you wanted.
29
+
30
+ **Quota is relative to whoever runs the skill.** Every backend spends its own
31
+ CLI's login. A backend on the same provider as you (`anthropic-claude/*` for a
32
+ Claude-based agent) drains the pool you are already burning, so it buys no extra
33
+ capacity and no independent perspective. That is why it is a last resort rather
34
+ than merely a choice.
35
+
36
+ **Seats pin exact model versions.** A vendor alias like `opus` moves under you
37
+ when a release lands, silently changing what a documented pipeline does.
38
+
39
+ **Some commands write files, some print.** `plan`, `review` and `image-gen`
40
+ produce artifacts worth keeping and re-reading, so they take `--out` and keep
41
+ stdout to a verdict line. `subagent` returns an answer you consume immediately,
42
+ and `implement`'s output IS the working tree.
43
+
44
+ **The CLI catches fake successes, not bad work.** Backends fail in ways that
45
+ look like success: an agy model with no quota returns an empty answer and exit 0;
46
+ codex sometimes draws a tiny image in code instead of rendering one. So a
47
+ too-small render is rejected as fake, an empty answer is an error, and an
48
+ `implement` that changed nothing exits 1. A review with no report file fails as
49
+ well, because a verdict without evidence is not a review. None of that judges
50
+ the work itself, which is why you still re-run the real gates on a diff.
51
+
52
+ **Chroma keying is a fallback, not a feature.** Only codex renders true alpha.
53
+ On the JPEG seats aibridge asks for a flat backdrop and removes it locally,
54
+ which gives binary edges and eats any subject the same colour as the backdrop.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aibridge/cli",
3
- "version": "0.9.0",
4
- "description": "CLI that bridges tasks to AI CLIs on your machine (plan / implement / review / subagent / image-gen)",
3
+ "version": "0.10.1",
4
+ "description": "Agent instructions and CLI for delegating work to authenticated AI CLIs",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -31,16 +31,17 @@
31
31
  },
32
32
  "files": [
33
33
  "dist",
34
+ "instructions",
34
35
  "src"
35
36
  ],
36
37
  "dependencies": {
37
38
  "@stricli/core": "1.3.0",
38
39
  "sharp": "^0.35.3",
39
40
  "@aibridge/proc": "0.9.0",
40
- "@aibridge/driver-grok": "0.9.0",
41
- "@aibridge/driver-codex": "0.9.0",
42
41
  "@aibridge/driver-agy": "0.9.0",
43
- "@aibridge/driver-claude": "0.9.0"
42
+ "@aibridge/driver-codex": "0.9.0",
43
+ "@aibridge/driver-claude": "0.9.0",
44
+ "@aibridge/driver-grok": "0.9.0"
44
45
  },
45
46
  "devDependencies": {
46
47
  "tsdown": "0.22.14"
@@ -84,7 +84,16 @@ describe('stricli exit-code lock & routing', () => {
84
84
  const ctx = fakeCtx();
85
85
  await runCli(ctx, ['--help']);
86
86
  const output = ctx._stdout.join('');
87
- for (const cmd of ['plan', 'implement', 'review', 'subagent', 'image-gen', 'runs', 'quota']) {
87
+ for (const cmd of [
88
+ 'plan',
89
+ 'implement',
90
+ 'review',
91
+ 'subagent',
92
+ 'image-gen',
93
+ 'runs',
94
+ 'quota',
95
+ 'skill',
96
+ ]) {
88
97
  expect(output).toContain(cmd);
89
98
  }
90
99
  });
package/src/app.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { createRequire } from 'node:module';
2
1
  import { buildApplication, buildRouteMap, run } from '@stricli/core';
3
2
  import { imageGen } from './commands/image-gen/command.ts';
4
3
  import { implement } from './commands/implement/command.ts';
@@ -7,12 +6,11 @@ import { plan } from './commands/plan/command.ts';
7
6
  import { quota } from './commands/quota/command.ts';
8
7
  import { review } from './commands/review/command.ts';
9
8
  import { runs } from './commands/runs/command.ts';
9
+ import { skill } from './commands/skill/command.ts';
10
10
  import { subagent } from './commands/subagent/command.ts';
11
11
  import type { LocalContext } from './context.ts';
12
12
  import { normalizeExitCode } from './exitCode.ts';
13
-
14
- const require = createRequire(import.meta.url);
15
- const { version } = require('../package.json') as { version: string };
13
+ import { PACKAGE_VERSION } from './package.ts';
16
14
 
17
15
  const BRIEF =
18
16
  'Bridge tasks to the other AI CLIs on this machine — a plan → implement → review workflow, task delegation, and image generation (codex / agy / grok seats).';
@@ -27,6 +25,7 @@ const routes = buildRouteMap({
27
25
  runs,
28
26
  quota,
29
27
  models,
28
+ skill,
30
29
  },
31
30
  docs: {
32
31
  brief: BRIEF,
@@ -36,7 +35,7 @@ const routes = buildRouteMap({
36
35
  export const app = buildApplication(routes, {
37
36
  name: 'aibridge',
38
37
  versionInfo: {
39
- currentVersion: version,
38
+ currentVersion: PACKAGE_VERSION,
40
39
  },
41
40
  scanner: {
42
41
  // Accept --no-preflight / --no-tools while flag keys stay camelCase in TS
@@ -0,0 +1,28 @@
1
+ import { buildCommand } from '@stricli/core';
2
+ import type { LocalContext } from '../../context.ts';
3
+ import skillImpl from './impl.ts';
4
+
5
+ function skillCommand(this: LocalContext, _flags: Record<never, never>, topic?: string): void {
6
+ skillImpl.call(this, topic);
7
+ }
8
+
9
+ export const skill = buildCommand({
10
+ func: skillCommand,
11
+ parameters: {
12
+ flags: {},
13
+ positional: {
14
+ kind: 'tuple',
15
+ parameters: [
16
+ {
17
+ brief: 'Command-specific instructions to append to the router',
18
+ parse: String,
19
+ placeholder: 'topic',
20
+ optional: true,
21
+ },
22
+ ],
23
+ },
24
+ },
25
+ docs: {
26
+ brief: 'Print the canonical agent instructions bundled with this CLI',
27
+ },
28
+ });
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { LocalContext } from '../../context.ts';
3
+ import { PACKAGE_VERSION } from '../../package.ts';
4
+ import skillImpl from './impl.ts';
5
+
6
+ function fakeCtx(): LocalContext & { stdout: string[]; stderr: string[] } {
7
+ const stdout: string[] = [];
8
+ const stderr: string[] = [];
9
+ return {
10
+ process: {
11
+ stdout: {
12
+ write: (value: string) => {
13
+ stdout.push(value);
14
+ return true;
15
+ },
16
+ },
17
+ stderr: {
18
+ write: (value: string) => {
19
+ stderr.push(value);
20
+ return true;
21
+ },
22
+ },
23
+ exitCode: undefined,
24
+ } as unknown as NodeJS.Process,
25
+ stdout,
26
+ stderr,
27
+ };
28
+ }
29
+
30
+ describe('skill command', () => {
31
+ it('prints the router with an exact-version runner', () => {
32
+ const ctx = fakeCtx();
33
+ skillImpl.call(ctx);
34
+ const output = ctx.stdout.join('');
35
+
36
+ expect(output).toContain(`npx -y @aibridge/cli@${PACKAGE_VERSION}`);
37
+ expect(output).toContain('# aibridge');
38
+ expect(output).not.toContain('# plan —');
39
+ expect(ctx.process.exitCode).toBeUndefined();
40
+ });
41
+
42
+ it('appends command-specific instructions', () => {
43
+ const ctx = fakeCtx();
44
+ skillImpl.call(ctx, 'plan');
45
+ const output = ctx.stdout.join('');
46
+
47
+ expect(output).toContain('# aibridge');
48
+ expect(output).toContain('# plan — write a detailed implementation plan file');
49
+ });
50
+
51
+ it('rejects an unknown topic', () => {
52
+ const ctx = fakeCtx();
53
+ skillImpl.call(ctx, 'nope');
54
+
55
+ expect(ctx.process.exitCode).toBe(2);
56
+ expect(ctx.stderr.join('')).toContain('unknown topic "nope"');
57
+ expect(ctx.stdout).toEqual([]);
58
+ });
59
+ });
@@ -0,0 +1,60 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import type { LocalContext } from '../../context.ts';
3
+ import { PACKAGE_VERSION } from '../../package.ts';
4
+
5
+ const TOPICS = {
6
+ plan: 'reference/plan.md',
7
+ implement: 'reference/implement.md',
8
+ review: 'reference/review.md',
9
+ subagent: 'reference/subagent.md',
10
+ 'image-gen': 'reference/image-gen.md',
11
+ why: 'reference/why.md',
12
+ } as const;
13
+
14
+ export type SkillTopic = keyof typeof TOPICS;
15
+
16
+ function instructionPath(relativePath: string): URL {
17
+ const candidates = [
18
+ // Built package: dist/cli.mjs -> instructions/
19
+ new URL(`../instructions/${relativePath}`, import.meta.url),
20
+ // Source tree: src/commands/skill/impl.ts -> instructions/
21
+ new URL(`../../../instructions/${relativePath}`, import.meta.url),
22
+ ];
23
+ const found = candidates.find(candidate => existsSync(candidate));
24
+ if (!found) {
25
+ throw new Error(`bundled instruction file is missing: ${relativePath}`);
26
+ }
27
+ return found;
28
+ }
29
+
30
+ function readInstruction(relativePath: string): string {
31
+ return readFileSync(instructionPath(relativePath), 'utf8').trimEnd();
32
+ }
33
+
34
+ export default function skillImpl(this: LocalContext, topic?: string): void {
35
+ if (topic !== undefined && !(topic in TOPICS)) {
36
+ this.process.stderr.write(
37
+ `aibridge skill: unknown topic ${JSON.stringify(topic)}; expected one of: ${Object.keys(TOPICS).join(', ')}\n`,
38
+ );
39
+ this.process.exitCode = 2;
40
+ return;
41
+ }
42
+
43
+ try {
44
+ const runner = `npx -y @aibridge/cli@${PACKAGE_VERSION}`;
45
+ const sections = [
46
+ `Command runner for these instructions: \`${runner}\`\nUse that exact prefix for every aibridge command below; do not substitute a global binary.`,
47
+ readInstruction('SKILL.md'),
48
+ ];
49
+
50
+ if (topic !== undefined) {
51
+ sections.push(readInstruction(TOPICS[topic as SkillTopic]));
52
+ }
53
+
54
+ this.process.stdout.write(`${sections.join('\n\n---\n\n')}\n`);
55
+ } catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ this.process.stderr.write(`aibridge skill: ${message}\n`);
58
+ this.process.exitCode = 1;
59
+ }
60
+ }
package/src/package.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+
5
+ export const PACKAGE_VERSION = (require('../package.json') as { version: string }).version;