From 6d454b078783b9a2604704613458b0dc7cb3b8b8 Mon Sep 17 00:00:00 2001 From: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> Date: Thu, 13 Aug 2026 06:38:00 -0700 Subject: [PATCH 1/2] docs: add provider pinning quickstart guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds comprehensive user-facing documentation for the experimental /provider model-pinning feature, covering: - Mental model: each provider entry combines one account + one model - Worked example with two real Anthropic accounts and four models - Configuration, naming guidance, and default precedence via priority - Interactive usage: /provider, /provider use , /provider auto - Limits: same-vendor only, session-only, top-level-only, orchestrator-dependent - Comparison table for three related but distinct 'provider' surfaces All instructions verified against live container with two real Anthropic accounts. Closes #267 and #268. ๐Ÿค– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- docs/PROVIDER_PINNING.md | 195 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 docs/PROVIDER_PINNING.md diff --git a/docs/PROVIDER_PINNING.md b/docs/PROVIDER_PINNING.md new file mode 100644 index 00000000..0ca16857 --- /dev/null +++ b/docs/PROVIDER_PINNING.md @@ -0,0 +1,195 @@ +# Switching models mid-conversation + +**Experimental.** `/provider use ` changes which model answers you, without +restarting your session. `/provider auto` puts it back. + +--- + +## The idea in one line + +Each entry in your provider list is **one account plus one model**, and you give it +a short name you can type. + +That means "my work account's Opus" and "my personal account's Opus" are two +entries, not one. So are "Opus" and "Haiku" on the same account. + +--- + +## Step 1 โ€” set up your providers + +Providers live in `~/.amplifier/settings.yaml` under `config.providers`. Here is a +real, working example: **two different Anthropic accounts**, four models, four +names you can type. + +```yaml +config: + providers: + # --- main account --- + - id: opus + module: provider-anthropic + config: + api_key: ${ANTHROPIC_API_KEY} + default_model: claude-opus-5 + priority: 1 # lowest number wins -> this is your default + + - id: sonnet + module: provider-anthropic + config: + api_key: ${ANTHROPIC_API_KEY} + default_model: claude-sonnet-5 + priority: 2 + + - id: haiku + module: provider-anthropic + config: + api_key: ${ANTHROPIC_API_KEY} + default_model: claude-haiku-4-5 + priority: 3 + + # --- second account, different key --- + - id: fable + module: provider-anthropic + config: + api_key: ${ANTHROPIC_FABLE_API_KEY} # <- the only thing that differs + default_model: claude-fable-5 + priority: 4 +``` + +Two things are doing all the work: + +| Field | What it does | +|---|---| +| `id` | The name you type: `/provider use fable` | +| `priority` | Lowest number is your default. Here that's `opus`. | + +Everything else โ€” the key, the model, the module โ€” is just configuration for that +one entry. + +Check it worked: + +```bash +amplifier provider list # should show all four, โ˜… on your default +amplifier provider test # confirms each key actually works +``` + +--- + +## Step 2 โ€” use it + +Inside an interactive session: + +``` +> /provider + ...shows what's available; โ˜… marks what your priority order favors + +> /provider use fable +๐Ÿ“Œ pinned: fable + experimental ยท scope: this conversation only ยท /provider for details + +[๐Ÿ“Œ fable]> what do you think of this design? + ...answered by claude-fable-5 + +[๐Ÿ“Œ fable]> /provider auto +unpinned (was fable) + +> โ† back to your default (opus) +``` + +While pinned, your prompt shows `[๐Ÿ“Œ fable]` and every reply's usage line ends with +`ยท ๐Ÿ“Œ pinned`. You never have to guess which model you're talking to. + +Note the usage line names the **model** (`claude-fable-5`), while the prompt names +your **id** (`fable`). If you ever give two entries the same model, the prompt is +the one that tells them apart. + +--- + +## Naming your providers + +The `id` is yours to choose. Pick names you'd actually want to type. + +```yaml +id: opus # short โ€” good when you have one account +id: fable # short โ€” the model IS the reason this entry exists + +id: opus-work # when the same model exists on two accounts +id: opus-home + +id: anthropic-home # when the account matters more than the model +``` + +A few things that help: + +- **Short beats descriptive.** You'll type this a lot. +- **Name what actually differs.** If you have one account, name by model + (`opus`, `haiku`). If you have several, add the account (`opus-work`). +- **`id` must be unique.** Two entries with the same `id` will collide. +- **`id` is optional** โ€” without it the name defaults to the module + (`anthropic`), which is fine for exactly one entry and confusing for more. + If you have more than one entry per provider, set `id` on all of them. + +--- + +## Setting your default + +Your default is simply the entry with the **lowest `priority` number**. + +To make Opus your default and keep Fable on hand, give Opus `priority: 1` and +Fable a higher number. `/provider auto` always returns you to whatever this says. + +Nothing about pinning changes your default โ€” a pin lasts for the session and +disappears when you exit. To change your default permanently, edit +`settings.yaml` (or use `amplifier provider edit`). + +--- + +## Limits worth knowing + +**Same vendor only.** You can switch freely among Anthropic entries, or among +OpenAI entries โ€” but not from Anthropic to OpenAI mid-conversation. Your +conversation history contains vendor-specific data that other vendors reject, +and switching across vendors can leave a session unable to continue. Amplifier +refuses the switch up front and tells you why. + +To use a different vendor, start a new session with `amplifier run -p `. + +**Session only.** A pin lasts until you exit. It does not persist and does not +change your saved settings. + +**Top-level only.** Pinning affects the conversation you're having. Sub-agents, +model-role routing, and `/goal` are unaffected โ€” they keep using whatever your +configuration says. + +**Depends on your orchestrator.** Pinning is a capability the orchestrator +provides, and not every orchestrator does. If yours doesn't, `/provider` tells +you plainly instead of pretending the switch worked. The default orchestrator +(`loop-streaming`) supports it. + +--- + +## Two `provider` commands, two jobs + +They look similar and do different things: + +| | Where | What it does | +|---|---|---| +| `amplifier provider ...` | Your shell | Manages saved configuration โ€” `add`, `edit`, `list`, `test`, `remove` | +| `/provider ...` | Inside a session | Pins the current conversation โ€” `use`, `auto`. Changes nothing on disk. | +| `amplifier run -p ` | Your shell | Starts one session on a specific provider | + +Rule of thumb: **`amplifier provider`** changes what's available tomorrow. +**`/provider`** changes who's answering right now. + +--- + +## Quick reference + +``` +/provider show providers and what's active +/provider use pin this conversation to +/provider auto unpin โ€” back to your default + +amplifier provider list show configured providers +amplifier provider test check every key works +amplifier run -p start a session on +``` From d18f5111f80dd85cae7a70d233fcaa4757c4cfa8 Mon Sep 17 00:00:00 2001 From: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> Date: Fri, 14 Aug 2026 12:27:09 -0700 Subject: [PATCH 2/2] feat: add CLI expertise bundle overlay with on-demand expert agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a composable bundle overlay that provides every CLI session with an expert agent that answers questions about the CLI itself. The expert reads from six existing docs (PROVIDER_PINNING, CONTEXT_LOADING, INTERACTIVE_MODE, GOAL_COMMAND, OUTPUT_FORMATS, SPAWN_PRECEDENCE), loaded on-demand when spawned (16K tokens), paired with a thin awareness routing pointer (317 tokens) loaded every session to prevent guessing. Bundle structure (repo root, matching layout of amplifier/core/foundation): - behaviors/cli-expertise.yaml: composed behavior including the agent - agents/cli-expert.md: context-sink expert with @-mentions of six docs - context/cli-awareness.md: routing pointer, deliberately bounded token budget - bundle.md: marker file for nested-bundle detection Modified: - pyproject.toml: force-include bundle dirs into installed wheel at amplifier_app_cli/_bundle/ (not package root, to avoid shadow effects) - runtime/config.py: _build_app_cli_behaviors() resolves bundle from installed package location, composes behavior only (never bundle.md) Fix: commands/run.py error messages now point to valid commands (/provider list, /provider add, /provider --help instead of /provider use) Known costs documented in PR body: docs/ duplication in wheel, root bundle.md affects repo as nested-bundle, sdist untested. Refs: #267, #268, #269 ๐Ÿค– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- agents/cli-expert.md | 127 ++++++++++++++++++++++++++++ amplifier_app_cli/commands/run.py | 4 +- amplifier_app_cli/runtime/config.py | 109 ++++++++++++++++++++++++ behaviors/cli-expertise.yaml | 29 +++++++ bundle.md | 79 +++++++++++++++++ context/cli-awareness.md | 24 ++++++ pyproject.toml | 24 ++++++ 7 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 agents/cli-expert.md create mode 100644 behaviors/cli-expertise.yaml create mode 100644 bundle.md create mode 100644 context/cli-awareness.md diff --git a/agents/cli-expert.md b/agents/cli-expert.md new file mode 100644 index 00000000..b74b2db4 --- /dev/null +++ b/agents/cli-expert.md @@ -0,0 +1,127 @@ +--- +meta: + name: cli-expert + description: | + **THE authoritative expert on the Amplifier CLI application itself** โ€” the + `amplifier` command, its slash commands, provider/model switching, session + lifecycle, context loading, output formats, and what spawned sub-agents + inherit. Carries the reference docs that shipped with THIS installed CLI + version, so its answers match the binary the user is actually running. + + Use PROACTIVELY when the user asks how the CLI itself behaves, rather than + asking for help with their own code. CLI behavior is version-specific and + changes between releases โ€” answering from memory produces confident, wrong + instructions, which is the precise failure this agent exists to prevent. + + **Authoritative on:** `/provider`, provider pinning, switching models + mid-conversation, `amplifier provider`, `/config`, `/mode`, `/modes`, + `/goal`, autonomous continuation, stop conditions, `/fork`, `/save`, + `/rename`, `/clear`, `/status`, `/agents`, `/tools`, `/skills`, `/skill`, + `/allowed-dirs`, `/denied-dirs`, `/help`, interactive mode, session + resume, session state location, `@mention` context loading, bundle + context precedence, `amplifier bundle`, app bundles, `--output json`, + `--output json-trace`, output formats for automation, spawn-time + precedence, what tools and providers a sub-agent inherits + + **MUST be used for:** + - "How do I switch models / pin a provider / use a different model?" + - Any question naming a slash command or an `amplifier ` + - "Why did this session load that context / where does session state live?" + - Scripting or automating Amplifier (output formats, exit behavior) + - "What does a spawned agent inherit?" / delegation precedence questions + + + User wants a different model partway through a conversation + How do I switch models without losing this conversation? + I'll delegate to app-cli:cli-expert โ€” provider pinning and the + /provider command are its domain, and it carries the docs matching this + installed CLI version. + Model/provider switching is version-specific CLI behavior. The + root session should route rather than guess at flag names that may not + exist in this build. + + + + User is scripting Amplifier in CI + I need to parse Amplifier's output in a CI job โ€” what formats are there? + Let me bring in app-cli:cli-expert to cover the --output json + and json-trace formats and their schemas. + Output formats are a documented CLI contract; the expert owns + OUTPUT_FORMATS.md and can give exact, current field names. + + + + User is confused about sub-agent capabilities + Why doesn't my sub-agent have the tool I configured? + I'll consult app-cli:cli-expert โ€” spawn-time precedence + determines what a spawned agent inherits. + SPAWN_PRECEDENCE.md defines the three-level policy; this is a + CLI-application question, not a bug in the user's code. + + +model_role: general +--- + +# Amplifier CLI Expert + +You are the specialist consultant on the **Amplifier CLI application itself** โ€” +not on the user's project code, and not on the Amplifier kernel or bundle +authoring internals. + +**Execution model:** You run as a one-shot sub-session. Answer from the +reference documentation below and return complete, actionable guidance. + +**Version-matched authority:** The docs in your knowledge base shipped in the +same package as the CLI the user is running. Prefer them over anything you +recall about Amplifier from training โ€” where they disagree, the docs win. + +## Knowledge Base + +@app-cli:docs/PROVIDER_PINNING.md +@app-cli:docs/INTERACTIVE_MODE.md +@app-cli:docs/GOAL_COMMAND.md +@app-cli:docs/CONTEXT_LOADING.md +@app-cli:docs/OUTPUT_FORMATS.md +@app-cli:docs/SPAWN_PRECEDENCE.md + +Additional references you may `read_file` when a question needs them (paths +are relative to this bundle root): + +- `docs/AGENT_DELEGATION_IMPLEMENTATION.md` โ€” delegation internals +- `docs/decisions/` โ€” ADRs recording why defaults are what they are +- `docs/designs/` โ€” design docs for in-flight and shipped features + +## When Consulted + +1. **Identify the surface** โ€” is this a slash command, an `amplifier` + subcommand, a config setting, or session behavior? +2. **Ground the answer in the docs above.** Quote exact command names, flags, + and config keys rather than paraphrasing them. +3. **Give a concrete next step** โ€” the literal command or config edit to run. + +## Boundaries โ€” hand these off rather than guessing + +- **Bundle/agent authoring, behaviors, composition semantics** โ†’ that is + foundation's domain, not the CLI application's. +- **Kernel contracts, module protocols, hooks API** โ†’ core's domain. +- **The user's own project code** โ†’ the root session handles it. + +## Output Contract + +Your response MUST include: + +- The exact command, flag, or config key involved โ€” as written in the docs +- A concrete next step the user can run or edit +- An explicit flag when the docs do not cover the question + +**When the docs do not answer it, say so.** Your value is being right about +this CLI version. If the shipped documentation does not cover what was asked, +state plainly which docs you checked and that the behavior is undocumented, +and point at the relevant source path if you can identify it. Do not +reconstruct plausible-sounding flags or commands from general Amplifier +knowledge โ€” a confidently invented flag is worse than an honest gap, because +the user will run it. + +--- + +@foundation:context/shared/common-agent-base.md diff --git a/amplifier_app_cli/commands/run.py b/amplifier_app_cli/commands/run.py index f09af52b..679512ad 100644 --- a/amplifier_app_cli/commands/run.py +++ b/amplifier_app_cli/commands/run.py @@ -221,7 +221,7 @@ def run( console.print( "[red]Error:[/red] --model requires --provider\n" "Specify which provider to use: --provider anthropic --model claude-opus-4-6\n" - "Run 'amplifier provider use --help' for configuration options" + "Run 'amplifier provider list' to see your configured providers" ) sys.exit(1) @@ -256,7 +256,7 @@ def run( console.print( f"[red]Error:[/red] Provider '{provider}' not configured\n" f"Available providers: {', '.join(p.get('id') or p.get('instance_id') or p.get('module', '?').replace('provider-', '') for p in providers_list if isinstance(p, dict))}\n" - f"Run 'amplifier provider use --help' for configuration options" + "Add one with 'amplifier provider add', or see all options with 'amplifier provider --help'" ) sys.exit(1) diff --git a/amplifier_app_cli/runtime/config.py b/amplifier_app_cli/runtime/config.py index 17dfdfba..e66fdf95 100644 --- a/amplifier_app_cli/runtime/config.py +++ b/amplifier_app_cli/runtime/config.py @@ -86,6 +86,13 @@ def _on_progress(action: str, detail: str) -> None: # Always available - users choose to use /mode commands or not compose_behaviors.extend(_build_modes_behaviors()) + # CLI self-expertise (app-cli:cli-expert + a thin awareness pointer). + # Always composed: every session should be able to answer "how does + # this CLI work?" by delegating rather than guessing. Sourced from the + # installed package on disk, never a git URI, so the expert's docs + # always match the running CLI version. + compose_behaviors.extend(_build_app_cli_behaviors()) + # Notification behaviors (desktop and push notifications). The flags # object is the single source of truth for "is this enabled?" โ€” the # hook-override emitter in AppSettings.get_notification_hook_overrides() @@ -897,6 +904,108 @@ def _build_modes_behaviors() -> list[str]: ] +# The app-cli bundle overlay lives at the REPO ROOT (bundle.md, behaviors/, +# agents/, context/, docs/), matching how amplifier, amplifier-core, and +# amplifier-foundation lay out their overlays. +# +# Those repos are cloned into ~/.amplifier/cache, so their repo-root dirs are +# on disk at runtime. This repo is not -- it installs from a wheel -- so +# pyproject.toml force-includes the same tree into the wheel under +# `amplifier_app_cli/_bundle/`. Both layouts are therefore possible at +# runtime, and _find_app_cli_bundle_root() resolves whichever is present. +_APP_CLI_PACKAGE_DIR = Path(__file__).parent.parent +_APP_CLI_BEHAVIOR_RELPATH = "behaviors/cli-expertise.yaml" + + +def _find_app_cli_bundle_root() -> Path | None: + """Locate the app-cli bundle root for this install. + + Two supported layouts, checked in order: + + 1. ``/_bundle/`` -- installed wheel (force-included by + pyproject.toml). Checked first: when present it is authoritative. + 2. ``/..`` -- the repo root in a dev checkout / editable install, + where ``behaviors/`` sits beside ``amplifier_app_cli/``. + + Probing for the behavior file itself (not just the directory) means a + half-populated tree is treated as missing rather than silently yielding + an unloadable URI. + + Returns: + Bundle root directory, or None if neither layout is present. + """ + for candidate in (_APP_CLI_PACKAGE_DIR / "_bundle", _APP_CLI_PACKAGE_DIR.parent): + if (candidate / _APP_CLI_BEHAVIOR_RELPATH).is_file(): + return candidate + return None + + +def _build_app_cli_behaviors() -> list[str]: + """Return the CLI self-expertise behavior URI for composition. + + This wires up ``app-cli:cli-expert`` -- the expert consultant on the CLI + application itself (provider pinning, slash commands, sessions, context + loading, output formats, spawn precedence) -- plus a thin always-on + awareness pointer telling the root session to delegate CLI questions + rather than answer them from memory. + + Two deliberate choices, both load-bearing: + + 1. **Sourced from disk, never a git URI.** The path is computed from this + package's own location, exactly as ``_ensure_default_skills_dirs()`` + does for packaged skills. A CLI expert pinned at ``@main`` could + document flags the installed CLI does not have; resolving in-package + makes that version skew structurally impossible. + + 2. **Only the behavior, never the root ``bundle.md``.** ``Bundle.compose()`` + replaces the instruction whenever the composed bundle has a non-empty + markdown body (foundation ``_dataclass.py``: ``if other.instruction: + result.instruction = other.instruction``). ``bundle.md`` has a body; + the behavior YAML does not. Composing the root bundle here would + silently clobber the user's system prompt. + + The ``file://`` scheme is required -- ``parse_uri()`` only extracts the + ``#subdirectory=`` fragment for ``file://`` URIs. A bare absolute path + with a fragment is parsed as a single literal path and fails to resolve. + + Returns: + Single-element list with the behavior URI. + + Raises: + RuntimeError: If the bundle overlay is missing from this install. + This is deliberately fatal rather than a warning-and-skip. The + behavior composition loop in + ``lib/bundle_loader/prepare.py`` catches per-behavior load + failures and continues, so a bad URI returned from here would be + swallowed and the expert would silently vanish -- exactly the + failure mode that is hardest to notice and worst to ship. A + missing overlay means the wheel was built without the + ``force-include`` block in pyproject.toml, which is a packaging + regression that should surface on the first run, not in a bug + report six weeks later. + """ + bundle_root = _find_app_cli_bundle_root() + if bundle_root is None: + searched = " and ".join( + str(candidate / _APP_CLI_BEHAVIOR_RELPATH) + for candidate in ( + _APP_CLI_PACKAGE_DIR / "_bundle", + _APP_CLI_PACKAGE_DIR.parent, + ) + ) + raise RuntimeError( + "amplifier-app-cli is missing its bundle overlay " + f"({_APP_CLI_BEHAVIOR_RELPATH}). Searched: {searched}. " + "This install cannot provide the app-cli:cli-expert agent. " + "If this is a built wheel, the [tool.hatch.build.targets.wheel." + "force-include] block in pyproject.toml is missing or wrong; " + "if this is a source checkout, the repo-root behaviors/ " + "directory is absent." + ) + + return [f"file://{bundle_root}#subdirectory={_APP_CLI_BEHAVIOR_RELPATH}"] + + def _build_notification_behaviors(flags: NotificationFlags) -> list[str]: """Build list of notification behavior URIs based on resolved flags. diff --git a/behaviors/cli-expertise.yaml b/behaviors/cli-expertise.yaml new file mode 100644 index 00000000..47ab1d39 --- /dev/null +++ b/behaviors/cli-expertise.yaml @@ -0,0 +1,29 @@ +bundle: + name: behavior-cli-expertise + version: 0.1.0 + description: | + Adds an expert consultant on the Amplifier CLI application itself โ€” + provider pinning, slash commands, sessions, context loading, output + formats, and spawn precedence. + +agents: + include: + - app-cli:cli-expert + +# Thin awareness pointer ONLY. +# +# The heavy reference docs (docs/PROVIDER_PINNING.md, docs/CONTEXT_LOADING.md, +# docs/INTERACTIVE_MODE.md, docs/GOAL_COMMAND.md, docs/OUTPUT_FORMATS.md, +# docs/SPAWN_PRECEDENCE.md) are @-mentioned in the cli-expert AGENT BODY, so +# they load only when that agent is spawned (context-sink pattern). +# +# The file below is a routing pointer, not documentation: it tells the root +# session that this domain exists and to delegate. It must stay well under +# the 1,000-token behavior context.include ceiling that foundation's +# validate-bundle-repo context-sink-compliance check enforces. +# +# This behavior is composed onto EVERY CLI session, so every token here is +# paid on every turn of every session. Do not grow it. +context: + include: + - app-cli:context/cli-awareness.md diff --git a/bundle.md b/bundle.md new file mode 100644 index 00000000..5065da5e --- /dev/null +++ b/bundle.md @@ -0,0 +1,79 @@ +--- +bundle: + name: app-cli + version: 0.1.0 + description: > + Expert consultant for the Amplifier CLI application itself โ€” provider + pinning, slash commands, sessions, context loading, output formats, + and spawn precedence. + +# Include this repo's own behavior by default, so loading the bundle directly +# gets the same capability the CLI auto-composes. (The CLI composes the +# BEHAVIOR yaml, not this file โ€” see behaviors/cli-expertise.yaml.) +includes: + - bundle: app-cli:behaviors/cli-expertise +--- + +# Amplifier CLI Bundle + +A bundle **overlaid on the existing `amplifier-app-cli` repo** โ€” `behaviors/`, +`agents/`, and `context/` sit at the repo root as siblings of the +`amplifier_app_cli/` Python package and of `docs/`, matching every other repo +in the ecosystem (`amplifier`, `amplifier-core`, `amplifier-foundation`). + +## Why the expert lives in this repo + +A CLI expert's authority is only as good as its version match with the +installed CLI. A separately-versioned bundle pinned at `@main` can document +`/provider` behavior the installed CLI does not have, or miss behavior it +does. Shipping here makes that skew structurally impossible: the expert that +answers your question is the one that shipped in your wheel. + +`docs/` being a natural sibling is the payoff โ€” `agents/cli-expert.md` +@-mentions the repo's real, canonical docs. There is no copy to drift. + +## How it reaches an installed user + +Sibling repos are *cloned* into `~/.amplifier/cache/`, so their repo-root +bundle dirs are on disk at runtime. **This repo is not** โ€” it is installed +with `uv tool install`, which ships only the wheel. + +So `pyproject.toml` force-includes these dirs into the wheel under +`amplifier_app_cli/_bundle/`: + +``` +[tool.hatch.build.targets.wheel.force-include] +"bundle.md" = "amplifier_app_cli/_bundle/bundle.md" +"behaviors" = "amplifier_app_cli/_bundle/behaviors" +"agents" = "amplifier_app_cli/_bundle/agents" +"context" = "amplifier_app_cli/_bundle/context" +"docs" = "amplifier_app_cli/_bundle/docs" +``` + +The repo root stays the single source of truth; the wheel carries a copy. +`_build_app_cli_behaviors()` in `amplifier_app_cli/runtime/config.py` resolves +whichever layout is present โ€” `_bundle/` when installed, repo root in a dev +checkout โ€” and **raises** if neither is found, so a packaging regression is +loud rather than a silently missing expert. + +The target is `_bundle/` *inside* the package deliberately: force-including +to a top-level `amplifier_app_cli/agents` would create a directory with no +`__init__.py` that shadows the real package namespace. + +## Structure + +``` +amplifier-app-cli/ +โ”œโ”€โ”€ bundle.md # this file โ€” namespace: app-cli +โ”œโ”€โ”€ behaviors/cli-expertise.yaml # the composable capability +โ”œโ”€โ”€ agents/cli-expert.md # context sink: @-mentions docs/ +โ”œโ”€โ”€ context/cli-awareness.md # thin always-on pointer +โ”œโ”€โ”€ docs/ # the repo's existing canonical docs +โ””โ”€โ”€ amplifier_app_cli/ # the Python package +``` + +## Scope + +This bundle answers "how does the Amplifier CLI work?" It deliberately does +**not** promote features or surface tips โ€” that is a separate concern and +belongs in a separate bundle. diff --git a/context/cli-awareness.md b/context/cli-awareness.md new file mode 100644 index 00000000..8be4abd0 --- /dev/null +++ b/context/cli-awareness.md @@ -0,0 +1,24 @@ +# Amplifier CLI: there is an expert for this + +You are running inside the **Amplifier CLI application**. The CLI itself โ€” +its commands, flags, config, and session machinery โ€” is a domain with a +dedicated expert that carries the authoritative, version-matched docs. + +**Delegate to `app-cli:cli-expert`** when the user asks how the CLI itself +behaves. Signals include: + +- Switching models or providers, provider pinning, `/provider`, `amplifier provider` +- Slash commands (`/config`, `/mode`, `/goal`, `/fork`, `/skills`, `/agents`, `/status`) +- Sessions: resuming, saving, forking, naming, where session state lives +- Bundles and skills: what is loaded, precedence, `amplifier bundle` +- `@mention` context loading and which files a session actually loaded +- Output formats (`--output json`, json-trace) and automation +- What tools/providers a spawned sub-agent inherits + +**Do not answer these from memory.** CLI behavior is version-specific and +changes between releases; the expert holds the docs that shipped with *this* +installed CLI. Guessing produces confident, wrong instructions โ€” the exact +failure this expert exists to prevent. + +If the question is about *your own task* (writing code, debugging the user's +project), that is not this domain โ€” handle it normally. diff --git a/pyproject.toml b/pyproject.toml index a6b9d2e9..c1654f1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,30 @@ package = true [tool.hatch.build.targets.wheel] packages = ["amplifier_app_cli"] +# Ship the repo-root bundle overlay (bundle.md + behaviors/ + agents/ + +# context/ + docs/) inside the wheel. +# +# Sibling repos (amplifier, amplifier-core, amplifier-foundation) put these +# dirs at their repo root too, but they are CLONED into ~/.amplifier/cache, +# so their whole tree is on disk at runtime. This repo is installed with +# `uv tool install` -- only the wheel ships -- so without this block the +# overlay would reach a dev checkout and nobody else. +# +# docs/ is included because agents/cli-expert.md @-mentions it; the repo root +# stays the single source of truth and the wheel carries a copy. +# +# Targets are under `_bundle/` INSIDE the package deliberately. Targeting +# `amplifier_app_cli/agents` would create a directory with no __init__.py +# that shadows the real package namespace and breaks `import amplifier_app_cli` +# in built wheels (see foundation BUNDLE_GUIDE.md, "force-include Shadowing +# Python Namespace"). Resolution lives in runtime/config.py. +[tool.hatch.build.targets.wheel.force-include] +"bundle.md" = "amplifier_app_cli/_bundle/bundle.md" +"behaviors" = "amplifier_app_cli/_bundle/behaviors" +"agents" = "amplifier_app_cli/_bundle/agents" +"context" = "amplifier_app_cli/_bundle/context" +"docs" = "amplifier_app_cli/_bundle/docs" + [tool.hatch.metadata] allow-direct-references = true