- `bottle:` in agent frontmatter is now optional; agents without it
are portable and require bottles to be selected at launch.
- Adds `filter_multiselect` to `tui.py`: multi-select picker with
ordered selection list, Space/Enter to toggle, Ctrl-D to confirm.
- `ManifestIndex` gains `all_bottle_names` and `load_for_agent` accepts
`bottle_names: tuple[str, ...]` to merge bottles in order at runtime.
- `merge_bottles_runtime` in `manifest_extends.py` applies the same
field-merge rules as `extends:` to pre-resolved bottle objects.
- `BottleSpec` gains `bottle_names`; `_validate` and `write_launch_metadata`
thread it through so `resume` replays the same bottle configuration.
- `cmd_start` shows the bottle multiselect after agent selection,
pre-populated from the agent's `bottle:` field when present.
- Existing agents with `bottle:` declared continue to work unchanged.
- Add type: ignore annotations for dict key validation
- Keys parameter is untyped object from YAML parsing
- Use type: ignore for set operations and sorted calls
- Fixes 4 pyright errors
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Rename _manifest_util.py → manifest_util.py (module isn't private)
- Rename _as_json_object → as_json_object, _parse_git_upstream → parse_git_upstream,
_parse_git_gate_config → parse_git_gate_config,
_validate_unique_git_names → validate_unique_git_names,
_validate_egress_routes → validate_egress_routes (none are private at
module boundary — underscore prefix was a carry-over from the old
monolithic manifest.py where everything lived in one namespace)
- Move _is_ip_literal → util.is_ip_literal (generic, belongs in the
top-level util module)
- Update all import sites across manifest_*.py, manifest_extends.py,
manifest_schema.py; existing callers of manifest.py are unaffected
All 867 unit tests pass.
Closes#157. Distributes the 1,026-line manifest.py across four
focused modules:
- _manifest_util.py: ManifestError + _as_json_object (shared base)
- manifest_git.py: GitEntry, GitUser, git-gate config helpers
- manifest_egress.py: EgressRoute, EgressConfig, PipelockRoutePolicy
- manifest_agent.py: AgentProvider, Agent
manifest.py is now the residual orchestration layer: Bottle, Manifest,
and re-exports of all public names so existing callers are unaffected.
All 867 unit tests pass.