agent-bios 0.8.0 → 0.9.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
|
@@ -68,7 +68,7 @@ agent-bios uninstall # remove deployed files and the zsh hook
|
|
|
68
68
|
|
|
69
69
|
From a git clone, run `./scripts/install.sh install` directly (the same CLI). `install` respects `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `AGENT_LAUNCH_VENV`, and `ZDOTDIR`; `--dry-run` prints actions without changing anything. Deploy to **every active environment in one sitting** — a partial deploy leaves a shared global pointing at a guide some environment lacks; globals are English only. Replaced files are backed up under `~/.local/share/agent-bios/backups/<timestamp>/`, and the installed set is recorded in a manifest that `uninstall` consumes. The published npm package ships only the deploy set (never `settings.json`, `config.toml`, `ko/`, or `benchmarks/`).
|
|
70
70
|
|
|
71
|
-
In a TTY, zero-argument `codex` or `claude` opens the launch preflight. Every arrow-key TUI selection screen keeps the complete current setup in a fixed top panel, followed by the highlighted option's description and then the option list. Move with Up/Down, select with Enter, use Esc to return to the previous menu, and use `q` to cancel; Esc at the mode root also cancels. Each tier's model is chosen from the host's configured catalog, or via **Other** to type any model id the backend accepts; that text input preserves values that start with `q`, so Esc or Ctrl-C cancels immediately there, while submitting `q` cancels after Enter. The Textual preflight reflows to the terminal size, so there is no fixed minimum geometry. The root menu picks a mode — **
|
|
71
|
+
In a TTY, zero-argument `codex` or `claude` opens the launch preflight. Every arrow-key TUI selection screen keeps the complete current setup in a fixed top panel, followed by the highlighted option's description and then the option list. Move with Up/Down, select with Enter, use Esc to return to the previous menu, and use `q` to cancel; Esc at the mode root also cancels. Each tier's model is chosen from the host's configured catalog, or via **Other** to type any model id the backend accepts; that text input preserves values that start with `q`, so Esc or Ctrl-C cancels immediately there, while submitting `q` cancels after Enter. The Textual preflight reflows to the terminal size, so there is no fixed minimum geometry. The root menu picks a mode — **Software Engineer** (repo-scoped work that defers to the project's own AGENTS.md/CLAUDE.md: **Vanilla**, the bare CLI with no launch contract, tier bindings, or applied permissions, plus **Custom**; SE-specific review defaults arrive later), **Builder** (the tier presets: Balanced, Deep review, Fast batch, Solo with delegation off, plus Custom), **Session distill** — then a preset within it. Select **Custom** (in Software Engineer or Builder) to open a persistent settings hub for the main tier, review setup, host policy, and each tier binding. Every edit returns to that hub; **Start with these settings** is the final launch confirmation, **Save these settings globally and start** additionally persists the setup as a named preset (with host-scoped tier overrides) in your user config for reuse elsewhere, and **Exit without launching** cancels the launch. The rich preflight runs from a managed virtualenv (`scripts/provision-venv.sh`, at `~/.local/share/agent-launch/venv`) that the launcher re-execs into on the interactive path; when that venv is unavailable, or the call is non-interactive, or `TERM` is `dumb`/unset, the launcher falls back to numbered prompts, where `b` is the back command. Backend command names are resolved from the calling environment's `PATH`; shell functions are not re-entered. Codex child bindings are materialized as session-selected agent configs under the user cache, while Claude receives model and effort in `--agents` JSON when delegation is enabled. Review runs cross-family by default (`review_family`, default `cross`; `same` restores today's same-family projection): because the main's tiers are one model family, every dispatchable review route — native, onto, and ultracode — runs on the opposite family. The exception is `slash-review`, the host's own built-in review command (`/code-review` on Claude, with `ultra` for its deep multi-agent pass; `/review` on Codex): it needs no dependency and always resolves, but being the main's own command it cannot be dispatched cross-family, so under `cross` it runs as the same-family floor and its verdicts are labeled PROPOSED. A Claude main dispatches gpt/codex review (native via the `codex-run` reviewer wrapper resolved under `$CODEX_HOME/bin`, onto via an `llmOverride` to the configured openai seat, ultracode via the `$ultracode-for-codex` Codex skill); a Codex main dispatches Anthropic/Claude review (native via `claude -p --permission-mode plan`, onto via an `llmOverride` to the anthropic seat, ultracode via `claude --effort ultracode -p` — Claude Code's headless `/workflows` ultracode mode, verified accepted on claude 2.1.210). The concrete reviewer command, resolved absolute path, `llmOverride`, and opposite-family tier bindings are named in the injected session-start contract; cross-family reviewers are dispatched as read-only subprocesses, not CLI-native subagents, since neither CLI hosts the other family as a native subagent. When a cross-family route is unavailable at launch or unauthenticated at use time it degrades to same-family native subagent review labeled PROPOSED (family collapse) rather than blocking; a requested non-none review with no cross-family route and no same-family fallback (delegation off) stays fail-closed. Review setup means configured/requested; this launcher does not claim that review completed, and unavailable runtimes such as Ultrawork are not offered until integrated.
|
|
72
72
|
|
|
73
73
|
At the shell-wrapper boundary, every argument-bearing command (`codex exec ...`, `claude -p ...`) and every non-TTY invocation skips launch-profile projection and preserves caller arguments. The Claude direct path intentionally retains its wrapper default, `--dangerously-skip-permissions`. `codex --no-tui ...` / `claude --no-tui ...` explicitly take that direct path, and `AGENT_LAUNCH_TUI=0` disables zero-argument TUI interception for a process tree.
|
|
74
74
|
|
|
@@ -125,6 +125,13 @@ depends on it, pin it explicitly instead of trusting the environment.
|
|
|
125
125
|
leaving stale, unreferenced definitions live. After updating, re-read the
|
|
126
126
|
resource, check definitions and active references separately, and remove
|
|
127
127
|
the orphans explicitly.
|
|
128
|
+
- **A new revision is not live traffic**: on a runtime that pins traffic to a
|
|
129
|
+
named revision (e.g. Cloud Run with a fixed split), `gcloud run deploy` (or
|
|
130
|
+
the equivalent) creates the new revision but shifts no traffic to it — the
|
|
131
|
+
previous revision keeps serving until an explicit `gcloud run services
|
|
132
|
+
update-traffic`. Read the "deploy succeeded" message as "a revision exists",
|
|
133
|
+
not "the new code is serving"; verify the live traffic split before
|
|
134
|
+
concluding the deploy took effect.
|
|
128
135
|
- **Perimeter controls need the enforcement point's own logs**: an agent-side
|
|
129
136
|
fetch is not an independent external observer — its egress IP and caching
|
|
130
137
|
path are opaque, and it may share the protected network or serve a stale
|
|
@@ -125,6 +125,13 @@ depends on it, pin it explicitly instead of trusting the environment.
|
|
|
125
125
|
leaving stale, unreferenced definitions live. After updating, re-read the
|
|
126
126
|
resource, check definitions and active references separately, and remove
|
|
127
127
|
the orphans explicitly.
|
|
128
|
+
- **A new revision is not live traffic**: on a runtime that pins traffic to a
|
|
129
|
+
named revision (e.g. Cloud Run with a fixed split), `gcloud run deploy` (or
|
|
130
|
+
the equivalent) creates the new revision but shifts no traffic to it — the
|
|
131
|
+
previous revision keeps serving until an explicit `gcloud run services
|
|
132
|
+
update-traffic`. Read the "deploy succeeded" message as "a revision exists",
|
|
133
|
+
not "the new code is serving"; verify the live traffic split before
|
|
134
|
+
concluding the deploy took effect.
|
|
128
135
|
- **Perimeter controls need the enforcement point's own logs**: an agent-side
|
|
129
136
|
fetch is not an independent external observer — its egress IP and caching
|
|
130
137
|
path are opaque, and it may share the protected network or serve a stale
|
package/config/agent-launch.toml
CHANGED
|
@@ -116,7 +116,7 @@ claude_permission_mode = "bypassPermissions"
|
|
|
116
116
|
[presets.vanilla]
|
|
117
117
|
label = "Vanilla"
|
|
118
118
|
description = "Plain CLI session: no launch contract, no tier bindings, standard permissions — exactly what the bare backend gives you."
|
|
119
|
-
mode = "
|
|
119
|
+
mode = "software-engineer"
|
|
120
120
|
main_tier = "helm"
|
|
121
121
|
frontier_effort = "max"
|
|
122
122
|
review_setup = "none"
|
package/config/promotions.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-bios",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A thin, low-level instruction layer for LLM CLI agents: one set of principles and behavior whichever model you run. Deploys into $HOME by copy via an explicit `agent-bios install`.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-bios": "scripts/install.sh"
|
package/scripts/agent-launch.py
CHANGED
|
@@ -44,17 +44,19 @@ EFFORT_DESCRIPTIONS = {
|
|
|
44
44
|
}
|
|
45
45
|
CUSTOM_PRESET = "__custom__"
|
|
46
46
|
OTHER_MODEL = "__other_model__"
|
|
47
|
-
# Root-menu grouping for presets: "builder" (tunable
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
|
|
47
|
+
# Root-menu grouping for presets: "builder" (tunable tier presets, includes
|
|
48
|
+
# Custom), "software-engineer" (repo-scoped work under the project's own
|
|
49
|
+
# AGENTS.md/CLAUDE.md — the bare Vanilla session plus Custom), "distill" (opens
|
|
50
|
+
# the Session Distill hub). A preset with a missing/unknown mode defaults to
|
|
51
|
+
# "builder" so presets written before this field existed (including saved/local
|
|
52
|
+
# user presets, and any that still carry the former "general" value) keep working.
|
|
53
|
+
SWE_MODE = "software-engineer"
|
|
52
54
|
DEFAULT_PRESET_MODE = "builder"
|
|
53
55
|
# The mode value that opens the Session Distill hub instead of a preset
|
|
54
56
|
# submenu; doubles as the option value on the root Mode menu so selecting it
|
|
55
57
|
# needs no translation.
|
|
56
58
|
DISTILL_MODE = "distill"
|
|
57
|
-
PRESET_MODES = (
|
|
59
|
+
PRESET_MODES = (SWE_MODE, DEFAULT_PRESET_MODE, DISTILL_MODE)
|
|
58
60
|
# User-saved presets live beside the deployed config, in a file the installer
|
|
59
61
|
# neither deploys nor verifies, so they survive `agent-bios install`.
|
|
60
62
|
USER_PRESETS_NAME = "presets.local.toml"
|
|
@@ -1683,8 +1685,9 @@ def pick_mode_and_preset(
|
|
|
1683
1685
|
ui: TextualUI | None,
|
|
1684
1686
|
resume_mode: str | None,
|
|
1685
1687
|
) -> tuple[str, bool, str]:
|
|
1686
|
-
"""Root menu: a 3-way mode picker (
|
|
1687
|
-
distill), then that mode's preset submenu (
|
|
1688
|
+
"""Root menu: a 3-way mode picker (Software Engineer / Builder / Session
|
|
1689
|
+
distill), then that mode's preset submenu (Software Engineer and Builder
|
|
1690
|
+
both list Custom).
|
|
1688
1691
|
|
|
1689
1692
|
Esc in the submenu returns to the mode picker; Esc at the mode picker
|
|
1690
1693
|
cancels the launcher, matching the picker's prior root Esc/q semantics.
|
|
@@ -1698,10 +1701,11 @@ def pick_mode_and_preset(
|
|
|
1698
1701
|
if mode is None:
|
|
1699
1702
|
mode_options = [
|
|
1700
1703
|
MenuOption(
|
|
1701
|
-
|
|
1702
|
-
"
|
|
1703
|
-
"
|
|
1704
|
-
"
|
|
1704
|
+
SWE_MODE,
|
|
1705
|
+
"Software Engineer",
|
|
1706
|
+
"Repo-scoped work that defers to the project's own "
|
|
1707
|
+
"AGENTS.md/CLAUDE.md: a bare Vanilla session, or Custom to "
|
|
1708
|
+
"configure one.",
|
|
1705
1709
|
),
|
|
1706
1710
|
MenuOption(
|
|
1707
1711
|
DEFAULT_PRESET_MODE,
|
|
@@ -1752,7 +1756,7 @@ def pick_mode_and_preset(
|
|
|
1752
1756
|
for name, data in presets.items()
|
|
1753
1757
|
if preset_mode(data) == mode
|
|
1754
1758
|
]
|
|
1755
|
-
if mode
|
|
1759
|
+
if mode in (DEFAULT_PRESET_MODE, SWE_MODE):
|
|
1756
1760
|
options.append(
|
|
1757
1761
|
MenuOption(
|
|
1758
1762
|
CUSTOM_PRESET,
|
|
@@ -1761,11 +1765,16 @@ def pick_mode_and_preset(
|
|
|
1761
1765
|
)
|
|
1762
1766
|
)
|
|
1763
1767
|
default = mode_default_preset(presets, mode) or CUSTOM_PRESET
|
|
1768
|
+
# Custom always starts from the builder default (an applied baseline), so a
|
|
1769
|
+
# Custom entered from Software Engineer mode applies its settings instead of
|
|
1770
|
+
# inheriting Vanilla's bare short-circuit. (SE-specific review defaults are
|
|
1771
|
+
# deferred; today Custom shares the builder baseline.)
|
|
1772
|
+
custom_base = mode_default_preset(presets, DEFAULT_PRESET_MODE) or default
|
|
1764
1773
|
if ui is not None and default != CUSTOM_PRESET:
|
|
1765
1774
|
ui.set_plan(build_plan(config, host, default))
|
|
1766
1775
|
|
|
1767
1776
|
def preview_preset(value: str) -> dict[str, Any]:
|
|
1768
|
-
target =
|
|
1777
|
+
target = custom_base if value == CUSTOM_PRESET else value
|
|
1769
1778
|
return build_plan(config, host, target)
|
|
1770
1779
|
|
|
1771
1780
|
try:
|
|
@@ -1776,7 +1785,7 @@ def pick_mode_and_preset(
|
|
|
1776
1785
|
mode = None
|
|
1777
1786
|
continue
|
|
1778
1787
|
if selected == CUSTOM_PRESET:
|
|
1779
|
-
return
|
|
1788
|
+
return custom_base, True, mode
|
|
1780
1789
|
return selected, False, mode
|
|
1781
1790
|
|
|
1782
1791
|
|
|
@@ -1804,6 +1813,13 @@ def select_plan(
|
|
|
1804
1813
|
plan = build_plan(config, host, selected_name)
|
|
1805
1814
|
if selected_custom:
|
|
1806
1815
|
plan["label"] = f"Custom ({plan['label']})"
|
|
1816
|
+
# A customized plan is always an applied setup, never the bare Vanilla
|
|
1817
|
+
# short-circuit — even if custom_base fell back to an SE-mode preset
|
|
1818
|
+
# under a stripped config with no builder presets. project_args
|
|
1819
|
+
# projects the bare backend iff mode == SWE_MODE, so force a Custom
|
|
1820
|
+
# launch out of that mode.
|
|
1821
|
+
if plan.get("mode") == SWE_MODE:
|
|
1822
|
+
plan["mode"] = DEFAULT_PRESET_MODE
|
|
1807
1823
|
if ui is not None:
|
|
1808
1824
|
ui.set_plan(plan)
|
|
1809
1825
|
if selected_custom:
|
|
@@ -2030,11 +2046,13 @@ def claude_agents(plan: dict[str, Any]) -> str:
|
|
|
2030
2046
|
|
|
2031
2047
|
def project_args(plan: dict[str, Any], materialize_agents: bool = True) -> list[str]:
|
|
2032
2048
|
host = plan["host"]
|
|
2033
|
-
if plan.get("mode") ==
|
|
2034
|
-
#
|
|
2035
|
-
# launch contract, no tier pinning, no agents, no
|
|
2036
|
-
# flag
|
|
2037
|
-
#
|
|
2049
|
+
if plan.get("mode") == SWE_MODE:
|
|
2050
|
+
# Software Engineer's Vanilla preset is the plain backend with nothing
|
|
2051
|
+
# applied: no launch contract, no tier pinning, no agents, no
|
|
2052
|
+
# permission/sandbox flag — it defers entirely to the repo's own
|
|
2053
|
+
# AGENTS.md/CLAUDE.md. Short-circuit so that invariant holds
|
|
2054
|
+
# structurally. Custom entered from this mode re-bases to the builder
|
|
2055
|
+
# default, so its plan mode is "builder" and its settings DO apply.
|
|
2038
2056
|
return []
|
|
2039
2057
|
main = plan["tiers"][plan["main_tier"]]
|
|
2040
2058
|
main_effort = tier_effort(plan, plan["main_tier"])
|
package/scripts/check-parity.sh
CHANGED
|
@@ -677,6 +677,93 @@ if launcher.is_file() and launch_profile:
|
|
|
677
677
|
if not scripted_ui.checked or not scripted_plan.get("_launch_confirmed"):
|
|
678
678
|
mark_fail("agent-launch scripted Custom hub did not reach final confirmation")
|
|
679
679
|
|
|
680
|
+
# Software Engineer mode: its submenu is exactly Vanilla + Custom; Vanilla
|
|
681
|
+
# stays the bare backend (no launch contract), while Custom re-bases to the
|
|
682
|
+
# applied builder baseline rather than inheriting Vanilla's bare
|
|
683
|
+
# short-circuit. Driven directly through pick_mode_and_preset — the root
|
|
684
|
+
# mode picker is TTY-only, so a piped/non-TTY run defaults past it.
|
|
685
|
+
class SEModeUI:
|
|
686
|
+
def __init__(self, pick):
|
|
687
|
+
self._pick = pick
|
|
688
|
+
self.submenu_labels = None
|
|
689
|
+
|
|
690
|
+
def set_plan(self, plan):
|
|
691
|
+
pass
|
|
692
|
+
|
|
693
|
+
def choose(self, title, options, default, allow_back, preview=None, corpus_lines=None):
|
|
694
|
+
if title == "Mode":
|
|
695
|
+
if launcher_module.SWE_MODE not in {option.value for option in options}:
|
|
696
|
+
mark_fail("agent-launch root menu is missing the Software Engineer mode")
|
|
697
|
+
return launcher_module.SWE_MODE
|
|
698
|
+
if title == "Preset":
|
|
699
|
+
self.submenu_labels = [option.label for option in options]
|
|
700
|
+
return self._pick
|
|
701
|
+
raise AssertionError(f"unexpected scripted menu: {title}")
|
|
702
|
+
|
|
703
|
+
se_vanilla_ui = SEModeUI("vanilla")
|
|
704
|
+
se_v_name, se_v_custom, _ = launcher_module.pick_mode_and_preset(
|
|
705
|
+
launch_profile, "codex", se_vanilla_ui, None
|
|
706
|
+
)
|
|
707
|
+
if se_vanilla_ui.submenu_labels != ["Vanilla", "Custom"]:
|
|
708
|
+
mark_fail(
|
|
709
|
+
"agent-launch Software Engineer submenu must be exactly Vanilla + "
|
|
710
|
+
f"Custom, got {se_vanilla_ui.submenu_labels}"
|
|
711
|
+
)
|
|
712
|
+
if se_v_custom or se_v_name != "vanilla":
|
|
713
|
+
mark_fail("agent-launch SE -> Vanilla must select the vanilla preset directly")
|
|
714
|
+
elif launcher_module.project_args(
|
|
715
|
+
launcher_module.build_plan(launch_profile, "codex", se_v_name),
|
|
716
|
+
materialize_agents=False,
|
|
717
|
+
):
|
|
718
|
+
mark_fail("agent-launch SE -> Vanilla must project the bare backend (no launch contract)")
|
|
719
|
+
|
|
720
|
+
se_custom_ui = SEModeUI(launcher_module.CUSTOM_PRESET)
|
|
721
|
+
se_c_name, se_c_custom, _ = launcher_module.pick_mode_and_preset(
|
|
722
|
+
launch_profile, "codex", se_custom_ui, None
|
|
723
|
+
)
|
|
724
|
+
if not se_c_custom:
|
|
725
|
+
mark_fail("agent-launch SE -> Custom must request the settings hub")
|
|
726
|
+
elif not launcher_module.project_args(
|
|
727
|
+
launcher_module.build_plan(launch_profile, "codex", se_c_name),
|
|
728
|
+
materialize_agents=False,
|
|
729
|
+
):
|
|
730
|
+
mark_fail("agent-launch SE -> Custom must project an applied setup, not the bare backend")
|
|
731
|
+
|
|
732
|
+
# Under a config with no builder presets, custom_base falls back to the SE
|
|
733
|
+
# default (vanilla), so SE -> Custom builds a plan in SWE_MODE; select_plan
|
|
734
|
+
# must force a customized plan out of that bare short-circuit so the user's
|
|
735
|
+
# settings are not silently discarded. Driven through the real select_plan.
|
|
736
|
+
class SECustomHubUI:
|
|
737
|
+
def set_plan(self, plan):
|
|
738
|
+
pass
|
|
739
|
+
|
|
740
|
+
def choose(self, title, options, default, allow_back, preview=None, corpus_lines=None):
|
|
741
|
+
if title == "Mode":
|
|
742
|
+
return launcher_module.SWE_MODE
|
|
743
|
+
if title == "Preset":
|
|
744
|
+
return launcher_module.CUSTOM_PRESET
|
|
745
|
+
if title == "Custom settings":
|
|
746
|
+
return "start"
|
|
747
|
+
raise AssertionError(f"unexpected scripted menu: {title}")
|
|
748
|
+
|
|
749
|
+
def prompt_text(self, label, default):
|
|
750
|
+
return default
|
|
751
|
+
|
|
752
|
+
stripped_profile = dict(launch_profile)
|
|
753
|
+
stripped_profile["presets"] = {
|
|
754
|
+
name: data
|
|
755
|
+
for name, data in launch_profile["presets"].items()
|
|
756
|
+
if name in ("vanilla", "session-distill")
|
|
757
|
+
}
|
|
758
|
+
stripped_custom_plan = launcher_module.select_plan(
|
|
759
|
+
stripped_profile, "codex", None, False, SECustomHubUI()
|
|
760
|
+
)
|
|
761
|
+
if not launcher_module.project_args(stripped_custom_plan, materialize_agents=False):
|
|
762
|
+
mark_fail(
|
|
763
|
+
"agent-launch SE -> Custom under a no-builder-preset config must still "
|
|
764
|
+
"project an applied setup (customization must not be silently discarded)"
|
|
765
|
+
)
|
|
766
|
+
|
|
680
767
|
with tempfile.TemporaryDirectory() as raw_tmp:
|
|
681
768
|
tmp = pathlib.Path(raw_tmp)
|
|
682
769
|
backend = tmp / "backend"
|
|
@@ -841,7 +928,7 @@ if launcher.is_file() and launch_profile:
|
|
|
841
928
|
os.close(master)
|
|
842
929
|
return bytes(transcript), picker_status
|
|
843
930
|
|
|
844
|
-
# Root menu is now a Mode picker (
|
|
931
|
+
# Root menu is now a Mode picker (Software Engineer / Builder / Session
|
|
845
932
|
# distill); Builder is the default highlight and lists Custom. Reaching
|
|
846
933
|
# Custom means: Enter the root to open Builder's preset submenu, then
|
|
847
934
|
# step down through its fixed presets (Balanced default-highlighted).
|
|
@@ -1217,7 +1304,7 @@ if launcher.is_file() and launch_profile:
|
|
|
1217
1304
|
# TERM=dumb routes to numbered prompts (textual renders on any usable
|
|
1218
1305
|
# terminal, so the numbered fallback is gated on TERM/non-TTY/textual
|
|
1219
1306
|
# availability, not a terminfo probe). 'b' is the numbered back command.
|
|
1220
|
-
# The root Mode menu is fixed (
|
|
1307
|
+
# The root Mode menu is fixed (Software Engineer=1, Builder=2, Session distill=3)
|
|
1221
1308
|
# regardless of preset count; only Custom's position within Builder's
|
|
1222
1309
|
# own preset submenu depends on how many builder-mode presets exist.
|
|
1223
1310
|
builder_preset_count = sum(
|
|
@@ -1590,7 +1677,7 @@ if launcher.is_file() and launch_profile:
|
|
|
1590
1677
|
"agent-launch Claude expert overrides were not appended last"
|
|
1591
1678
|
)
|
|
1592
1679
|
|
|
1593
|
-
# Vanilla (mode=
|
|
1680
|
+
# Vanilla (mode=software-engineer): the raw backend with nothing applied — no
|
|
1594
1681
|
# launch contract, no agents, no permission-bypass flag.
|
|
1595
1682
|
vanilla_configured = invoke([
|
|
1596
1683
|
sys.executable, str(launcher), "--preset", "vanilla", "--yes", "--dry-run",
|