Agent config init scripts for start of container#18
Conversation
📝 WalkthroughWalkthroughAdds per-agent pre-start "init" shell commands, a new Changes
Sequence DiagramsequenceDiagram
actor User
participant CLI as "vp run / vp config"
participant Config as "Config Loader"
participant Init as "Init Handler"
participant Docker as "DockerManager"
participant Container as "Container"
User->>CLI: vp run <agent>
CLI->>Config: load agent config
Config-->>CLI: returns agent config (may include init)
CLI->>Init: _agent_init_commands(agent, cfg)
Init-->>CLI: list of init commands
alt init commands present
CLI->>Init: _init_entrypoint(init_commands)
Init-->>CLI: entrypoint script (["/bin/sh","-lc","..."])
CLI->>Docker: resolve_launch_command(image, command)
Docker-->>CLI: resolved launch command
CLI->>Docker: run_agent(image, command=resolved, entrypoint=entrypoint)
else no init
CLI->>Docker: run_agent(image, command=maybe_overridden)
end
Docker->>Container: docker run (entrypoint, command)
Container->>Container: execute init script (set -e)
Container->>Container: execute agent startup
Container-->>User: agent running
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/vibepod/core/docker.py (1)
113-114: Defensively normalize explicit command overrides.
commandis typed aslist[str] | None, but normalizing it here avoids brittle behavior if non-list values are ever passed at runtime.Suggested refactor
- effective_cmd = command if command is not None else image_cmd + effective_cmd = _normalize_command(command) if command is not None else image_cmd🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/core/docker.py` around lines 113 - 114, Normalize the explicit command override before using it to build launch: ensure the variable used (currently `effective_cmd = command if command is not None else image_cmd`) is always a list of strings even if callers pass a string/tuple/other iterable at runtime; replace that assignment with a small normalization step that converts a string to [string], converts tuples or other iterables to list, and otherwise wraps non-iterable values into a single-element list, then use that normalized `effective_cmd` when constructing `launch = [*image_entrypoint, *effective_cmd]`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/configuration.md`:
- Around line 165-166: Add a clear, explicit trust warning to the description of
agents.<agent>.init: state that since agents.<agent>.init commands run inside
the container with `/bin/sh -lc` and `set -e` before the agent process starts,
any project config can execute arbitrary shell commands on every `vp run` (with
workspace and config mounts), so running configs from untrusted repositories is
unsafe and may lead to code execution or data compromise; mention recommended
mitigations (review config, run in isolated environment, avoid mounting
sensitive paths) and reference agents.<agent>.init and `vp run` so readers can
find the relevant section.
In `@src/vibepod/core/docker.py`:
- Around line 98-106: The images.get(...) block currently only catches NotFound
and APIError; add a final except DockerException as exc clause to convert any
other docker.errors.DockerException into a DockerClientError with a
user-friendly message. Specifically, update the try/except in the method using
self.client.images.get(image) to append: except DockerException as exc: raise
DockerClientError(f"Failed to inspect image {image}: {exc}") from exc so all
Docker SDK errors are translated to CLI-friendly DockerClientError.
In `@tests/test_config.py`:
- Around line 5-12: Reorder the imports in tests/test_config.py to satisfy Ruff
I001: put standard library imports first (Path from pathlib), then third-party
imports (CliRunner from typer.testing), then local/package imports
(SUPPORTED_AGENTS from vibepod.constants, app from vibepod.cli, and
deep_merge/get_config from vibepod.core.config); within each group, sort
alphabetically to match the linter expectations.
---
Nitpick comments:
In `@src/vibepod/core/docker.py`:
- Around line 113-114: Normalize the explicit command override before using it
to build launch: ensure the variable used (currently `effective_cmd = command if
command is not None else image_cmd`) is always a list of strings even if callers
pass a string/tuple/other iterable at runtime; replace that assignment with a
small normalization step that converts a string to [string], converts tuples or
other iterables to list, and otherwise wraps non-iterable values into a
single-element list, then use that normalized `effective_cmd` when constructing
`launch = [*image_entrypoint, *effective_cmd]`.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
README.mddocs/agents/index.mddocs/configuration.mddocs/quickstart.mdsrc/vibepod/commands/config.pysrc/vibepod/commands/run.pysrc/vibepod/core/config.pysrc/vibepod/core/docker.pytests/test_config.pytests/test_run.py
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/test_run.py (1)
41-52: Consider extracting a shared_FakeClientfixture.The
_FakeContainersand_FakeClientclasses are duplicated across multiple tests. A@pytest.fixtureor a module-level helper class could reduce boilerplate. This is a minor suggestion since the pattern is consistent with existing tests in the file.Also applies to: 90-103, 133-146
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_run.py` around lines 41 - 52, Duplicate test helpers _FakeContainers and _FakeClient are repeated; extract them into a single shared pytest fixture (e.g., a module-level fixture named fake_client) or a module-level helper class and replace the per-test duplicates with that fixture. Update tests that currently define _FakeContainers/_FakeClient (references: _FakeContainers.run and _FakeClient.containers) to accept the new fake_client fixture and use fake_client.containers.run to capture run_kwargs, and remove the duplicate class definitions at the other occurrences.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@tests/test_run.py`:
- Around line 41-52: Duplicate test helpers _FakeContainers and _FakeClient are
repeated; extract them into a single shared pytest fixture (e.g., a module-level
fixture named fake_client) or a module-level helper class and replace the
per-test duplicates with that fixture. Update tests that currently define
_FakeContainers/_FakeClient (references: _FakeContainers.run and
_FakeClient.containers) to accept the new fake_client fixture and use
fake_client.containers.run to capture run_kwargs, and remove the duplicate class
definitions at the other occurrences.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
docs/agents/index.mddocs/configuration.mdsrc/vibepod/commands/run.pysrc/vibepod/core/config.pysrc/vibepod/core/docker.pytests/test_config.pytests/test_run.py
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/agents/index.md
- docs/configuration.md
- tests/test_config.py
There was a problem hiding this comment.
Pull request overview
This PR adds two related features to VibePod: a vp config init command to bootstrap project-level config files, and support for per-agent initialization scripts (agents.<agent>.init) that run shell commands inside agent containers before the main process starts. The implementation wraps the container's original entrypoint in a /bin/sh -lc wrapper with set -e to run the init commands, then exec "$@" to hand off to the original process.
Changes:
- New
vp config initcommand that creates a minimal.vibepod/config.yamlwith--forceoverwrite support - Per-agent
initconfig key (default[]) and the corresponding shell entrypoint wrapping logic inrun.pyanddocker.py - Documentation and test coverage for both features
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/vibepod/commands/config.py |
Adds init subcommand to create minimal project config |
src/vibepod/commands/run.py |
Adds _agent_init_commands, _init_entrypoint helpers and wires them into the run flow |
src/vibepod/core/docker.py |
Adds resolve_launch_command method and entrypoint parameter to run_agent |
src/vibepod/core/config.py |
Adds init: [] to every agent's default config block |
tests/test_run.py |
New tests for entrypoint forwarding, init command validation, and launch command resolution |
tests/test_config.py |
New tests for config init command behavior and default config structure |
docs/quickstart.md |
Documents vp config init usage |
docs/configuration.md |
Documents project-level config init and agents.<agent>.init semantics |
docs/agents/index.md |
Documents init scripts section with examples |
README.md |
Adds vp config init to the feature list |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/vibepod/commands/run.py (1)
72-81: Init commands with special shell characters may break the entrypoint script.Commands containing newlines, unescaped quotes, or other shell metacharacters could corrupt the script. Since these come from trusted config, this is an edge case, but a malformed command could cause confusing failures.
Consider either:
- Escaping commands before embedding, or
- Documenting that init commands must be valid single-line shell commands
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/commands/run.py` around lines 72 - 81, The _init_entrypoint function currently injects init_commands directly into a shell -lc script which can break if commands contain newlines, quotes, or shell metacharacters; change it to emit the commands via a single-quoted here-document so the payload is preserved literally (no interpolation) before the exec "$@"; specifically, construct the script using a heredoc with a single-quoted delimiter (to avoid expansion of quotes/metacharacters) that contains the joined init_commands (from the init_commands parameter) and then the exec "$@" line, or alternatively validate/escape each entry in init_commands to ensure they are single-line shell-safe strings; update the _init_entrypoint return to use that safe script form.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/vibepod/commands/run.py`:
- Around line 72-81: The _init_entrypoint function currently injects
init_commands directly into a shell -lc script which can break if commands
contain newlines, quotes, or shell metacharacters; change it to emit the
commands via a single-quoted here-document so the payload is preserved literally
(no interpolation) before the exec "$@"; specifically, construct the script
using a heredoc with a single-quoted delimiter (to avoid expansion of
quotes/metacharacters) that contains the joined init_commands (from the
init_commands parameter) and then the exec "$@" line, or alternatively
validate/escape each entry in init_commands to ensure they are single-line
shell-safe strings; update the _init_entrypoint return to use that safe script
form.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
README.mddocs/agents/index.mddocs/configuration.mddocs/quickstart.mdsrc/vibepod/commands/config.pysrc/vibepod/commands/run.pysrc/vibepod/core/config.pysrc/vibepod/core/docker.pytests/test_config.pytests/test_run.py
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/quickstart.md
- docs/agents/index.md
- src/vibepod/core/config.py
This pull request adds support for per-agent initialization scripts in VibePod, allowing users to specify shell commands to run inside agent containers before the main process starts. It introduces the
agents.<agent>.initconfiguration option, updates documentation to explain this feature, and adds a newvp config initcommand to bootstrap project-level config files. The implementation includes robust validation, integration with the Docker entrypoint, and comprehensive tests.Example config:
Summary by CodeRabbit
New Features
vp config initto create a minimal project config (use--forceto overwrite).Documentation
vp config init, agentinitconfig, execution semantics, examples, and config merge/override behavior.Tests