@john-ezra/openralph 0.1.1 → 0.1.2
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/AGENTS.md +6 -6
- package/CHANGELOG.md +19 -0
- package/README.md +6 -5
- package/package.json +2 -2
- package/src/args.ts +1 -1
- package/src/docker.ts +9 -0
- package/src/launcher.ts +21 -3
package/AGENTS.md
CHANGED
|
@@ -8,7 +8,7 @@ OpenRalph is a light opencode plugin that implements the Ralph workflow from Cla
|
|
|
8
8
|
- Preserve Ralph's central mechanism: one fresh top-level opencode run per loop iteration.
|
|
9
9
|
- Use disk files as persistent state: `specs/*`, `AGENTS.md`, `IMPLEMENTATION_PLAN.md`, `PROMPT_plan.md`, and `PROMPT_build.md`; use `runs/*` only for durable local run artifacts and audit/debug output.
|
|
10
10
|
- Do not turn OpenRalph into a general sandbox or orchestration platform.
|
|
11
|
-
- Safety strategy is the user's responsibility. OpenRalph provides only lightweight guardrails and
|
|
11
|
+
- Safety strategy is the user's responsibility. OpenRalph provides only lightweight guardrails and default Dockerized loop execution with explicit host-mode opt-out.
|
|
12
12
|
- Avoid complex modes, safety matrices, Podman requirements, or heavy process abstractions.
|
|
13
13
|
|
|
14
14
|
## Ralph Phases
|
|
@@ -38,7 +38,7 @@ The server plugin should inject these commands only for authorized loop child pr
|
|
|
38
38
|
- Never use `--continue` for child runs.
|
|
39
39
|
- Always pass `--dir <project-root>` to child runs.
|
|
40
40
|
- Plan/build child runs use `--dangerously-skip-permissions`.
|
|
41
|
-
-
|
|
41
|
+
- Docker mode is enabled by default; host plan/build commands launch one Docker container and the full loop runs inside it unless `--no-docker` or `docker.enabled: false` is used.
|
|
42
42
|
- Docker mode runs the container `openralph plan` or `openralph build` CLI entrypoint, never public prompt command replay.
|
|
43
43
|
- Container loops set `OPENRALPH_IN_DOCKER=1` and require token-backed Docker attestation before running.
|
|
44
44
|
- Docker mode disables project OpenCode config and injects config that loads only image-bundled OpenRalph.
|
|
@@ -71,9 +71,9 @@ Plugin options:
|
|
|
71
71
|
|
|
72
72
|
```json
|
|
73
73
|
{
|
|
74
|
-
"defineModel": "heavy-model",
|
|
75
|
-
"planModel": "cheap-model",
|
|
76
|
-
"buildModel": "cheap-model",
|
|
74
|
+
"defineModel": "provider/heavy-model",
|
|
75
|
+
"planModel": "provider/cheap-model",
|
|
76
|
+
"buildModel": "provider/cheap-model",
|
|
77
77
|
"docker": {
|
|
78
78
|
"enabled": true,
|
|
79
79
|
"image": "openralph:local",
|
|
@@ -112,7 +112,7 @@ Use tags only after a successful build iteration with a new commit and clean wor
|
|
|
112
112
|
|
|
113
113
|
## Safety Posture
|
|
114
114
|
|
|
115
|
-
OpenRalph v1
|
|
115
|
+
OpenRalph v1 defaults to Dockerized execution for Plan and Build, with explicit host-mode opt-out.
|
|
116
116
|
|
|
117
117
|
Rationale:
|
|
118
118
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to OpenRalph will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on Keep a Changelog, and this project uses semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.2] - 2026-06-04
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Docker mode is now the default for Plan and Build; host mode requires `--no-docker` or `docker.enabled: false`.
|
|
14
|
+
- Missing default Docker images now fail before container launch with build and host-mode opt-out guidance.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Normalized the CLI bin path so npm preserves the `openralph` executable during publish.
|
|
19
|
+
|
|
20
|
+
## [0.1.1] - 2026-06-04
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Kept opencode plugin type definitions out of runtime dependencies.
|
|
25
|
+
|
|
7
26
|
## [0.1.0] - 2026-06-04
|
|
8
27
|
|
|
9
28
|
### Added
|
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ The normal install path is opencode's built-in plugin installer:
|
|
|
16
16
|
2. Run `Install plugin` from the command palette/plugins UI.
|
|
17
17
|
3. Enter `@john-ezra/openralph` at the `npm package name` prompt.
|
|
18
18
|
4. Leave scope as `local` for a project install, or press `Tab` to toggle to `global`.
|
|
19
|
-
5.
|
|
20
|
-
6.
|
|
19
|
+
5. Build the default Docker image with `bunx @john-ezra/openralph docker build`.
|
|
20
|
+
6. Restart opencode if needed.
|
|
21
|
+
7. Run `/ralph`.
|
|
21
22
|
|
|
22
23
|
CLI equivalent for non-TUI users:
|
|
23
24
|
|
|
@@ -80,11 +81,11 @@ TUI plugin in `tui.json`:
|
|
|
80
81
|
|
|
81
82
|
All model options are optional. Command `--model` values override plugin options. If no model is resolved, OpenRalph omits `--model` and lets opencode use its default.
|
|
82
83
|
|
|
83
|
-
Server and TUI plugin options use the same shape. Direct CLI/headless runs can pass the same launcher options through `OPENRALPH_OPTIONS_JSON`; without that env var, `openralph plan/build` uses default options, including Docker
|
|
84
|
+
Server and TUI plugin options use the same shape. Direct CLI/headless runs can pass the same launcher options through `OPENRALPH_OPTIONS_JSON`; without that env var, `openralph plan/build` uses default options, including Docker enabled with image `openralph:local` and `.env*` masking enabled.
|
|
84
85
|
|
|
85
86
|
## Docker Mode
|
|
86
87
|
|
|
87
|
-
Docker mode is
|
|
88
|
+
Docker mode is the default for Plan and Build. Plan and Build from `/ralph`, `openralph plan`, and `openralph build` launch one Docker container from the host and run the full Ralph loop inside it through the container `openralph` CLI entrypoint. Docker uses `--pull=never`, so build the default image locally before running Dockerized loops. To intentionally run on the host, pass `--no-docker` for that run or set `"docker": { "enabled": false }` in plugin options.
|
|
88
89
|
|
|
89
90
|
If you installed through opencode's plugin installer, the package bin may not be available on your shell `PATH`. Build the image with direct package execution:
|
|
90
91
|
|
|
@@ -134,7 +135,7 @@ Restart opencode after installing or changing `opencode.json`, `tui.json`, or pl
|
|
|
134
135
|
|
|
135
136
|
OpenRalph Plan and Build child iterations run `opencode run --dangerously-skip-permissions`. Treat the agent's actions as untrusted.
|
|
136
137
|
|
|
137
|
-
Host mode runs those child iterations directly on your machine with inherited environment variables, host filesystem access, and unrestricted network access.
|
|
138
|
+
Host mode runs those child iterations directly on your machine with inherited environment variables, host filesystem access, and unrestricted network access. Use `--no-docker` or `"docker": { "enabled": false }` only when you intentionally want that behavior.
|
|
138
139
|
|
|
139
140
|
Docker mode reduces host filesystem blast radius, but it is not a formal sandbox. The agent can read the mounted repository and the read-only mounted OpenCode auth file, and Docker mode does not restrict network egress. The `.env*` masking feature only replaces files whose basename starts with `.env`, except `.env.example`, `.env.sample`, `.env.template`, and `.env.dist`; it does not mask other in-repo secrets such as `.npmrc`, private keys, cloud credentials, or service-account JSON.
|
|
140
141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@john-ezra/openralph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Light opencode plugin for the Ralph workflow.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"./package.json": "./package.json"
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
|
-
"openralph": "
|
|
16
|
+
"openralph": "bin/openralph"
|
|
17
17
|
},
|
|
18
18
|
"engines": {
|
|
19
19
|
"bun": ">=1.2.0"
|
package/src/args.ts
CHANGED
|
@@ -112,7 +112,7 @@ export function formatLoopArgsForReplay(args: ParsedLoopArgs): string {
|
|
|
112
112
|
|
|
113
113
|
export function resolveDockerOptions(options: OpenRalphOptions): ResolvedDockerOptions {
|
|
114
114
|
return {
|
|
115
|
-
enabled: options.docker?.enabled ??
|
|
115
|
+
enabled: options.docker?.enabled ?? true,
|
|
116
116
|
image: options.docker?.image ?? DEFAULT_DOCKER_IMAGE,
|
|
117
117
|
maskEnv: options.docker?.maskEnv ?? true,
|
|
118
118
|
}
|
package/src/docker.ts
CHANGED
|
@@ -187,6 +187,15 @@ export async function buildLocalDockerImage(input: BuildLocalDockerImageInput =
|
|
|
187
187
|
}).result
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
export async function dockerImageExists(image: string, cwd = process.cwd()): Promise<boolean> {
|
|
191
|
+
const result = await startCommand("docker", ["image", "inspect", image], {
|
|
192
|
+
cwd,
|
|
193
|
+
streamOutput: false,
|
|
194
|
+
captureOutput: false,
|
|
195
|
+
}).result
|
|
196
|
+
return result.exitCode === 0
|
|
197
|
+
}
|
|
198
|
+
|
|
190
199
|
export function buildDockerArgs(input: BuildDockerArgsInput): string[] {
|
|
191
200
|
const configContent = buildContainerConfig(input.options, input.docker, input.imagePluginPath)
|
|
192
201
|
const args = [
|
package/src/launcher.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatLoopArgsForReplay, parseLoopArgs, resolveDockerOptions, validateOptions, type LoopPhase, type OpenRalphOptions, type ParsedLoopArgs } from "./args.ts"
|
|
2
|
-
import { CONTAINER_WORKSPACE, runDockerLoop } from "./docker.ts"
|
|
2
|
+
import { CONTAINER_WORKSPACE, dockerImageExists as defaultDockerImageExists, runDockerLoop } from "./docker.ts"
|
|
3
3
|
import { commandExists as defaultCommandExists, type CommandOutputEvent, type CommandResult } from "./exec.ts"
|
|
4
4
|
import { requireGitContext } from "./git.ts"
|
|
5
5
|
import { formatSummary, runLoop, type LoopSummary } from "./loop.ts"
|
|
@@ -32,6 +32,7 @@ export interface RunLauncherDeps {
|
|
|
32
32
|
runDockerLoop?: typeof runDockerLoop
|
|
33
33
|
runLoop?: typeof runLoop
|
|
34
34
|
commandExists?: typeof defaultCommandExists
|
|
35
|
+
dockerImageExists?: typeof defaultDockerImageExists
|
|
35
36
|
trust?: TrustDeps
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -55,6 +56,10 @@ export async function runOpenRalphLauncher(input: RunLauncherInput, deps: RunLau
|
|
|
55
56
|
await preflightCommands(mode, deps.commandExists ?? defaultCommandExists)
|
|
56
57
|
|
|
57
58
|
if (mode === "docker-host-launch") {
|
|
59
|
+
const docker = resolveDockerOptions(input.options)
|
|
60
|
+
const imageExists = await (deps.dockerImageExists ?? defaultDockerImageExists)(docker.image, input.cwd)
|
|
61
|
+
if (!imageExists) throw new Error(formatMissingDockerImage(input.phase, parsed, docker.image))
|
|
62
|
+
|
|
58
63
|
const git = await (deps.requireGitContext ?? requireGitContext)(input.cwd)
|
|
59
64
|
const result = await (deps.runDockerLoop ?? runDockerLoop)({
|
|
60
65
|
phase: input.phase,
|
|
@@ -192,7 +197,7 @@ function formatMissingCommands(commands: string[]): string {
|
|
|
192
197
|
const hints: Record<string, string> = {
|
|
193
198
|
git: "Install git and ensure it is on PATH.",
|
|
194
199
|
opencode: "Install opencode (https://opencode.ai) and ensure it is on PATH.",
|
|
195
|
-
docker: "Install Docker and ensure the docker executable is on PATH.",
|
|
200
|
+
docker: "Install Docker and ensure the docker executable is on PATH, or run this loop with --no-docker to opt into host mode.",
|
|
196
201
|
}
|
|
197
202
|
|
|
198
203
|
return [
|
|
@@ -201,9 +206,22 @@ function formatMissingCommands(commands: string[]): string {
|
|
|
201
206
|
].join("\n")
|
|
202
207
|
}
|
|
203
208
|
|
|
209
|
+
function formatMissingDockerImage(phase: LoopPhase, parsed: ParsedLoopArgs, image: string): string {
|
|
210
|
+
return [
|
|
211
|
+
`Docker image ${image} was not found.`,
|
|
212
|
+
"",
|
|
213
|
+
"OpenRalph defaults to Docker mode for safer loop execution and Docker runs with --pull=never.",
|
|
214
|
+
"Build the local image with:",
|
|
215
|
+
" bunx @john-ezra/openralph docker build",
|
|
216
|
+
"",
|
|
217
|
+
"If you intentionally want to run this loop on the host, rerun with:",
|
|
218
|
+
` ${noDockerCommand(phase, parsed)}`,
|
|
219
|
+
].join("\n")
|
|
220
|
+
}
|
|
221
|
+
|
|
204
222
|
function noDockerCommand(phase: LoopPhase, parsed: ParsedLoopArgs): string {
|
|
205
223
|
const replayArgs = formatLoopArgsForReplay(parsed)
|
|
206
|
-
return
|
|
224
|
+
return `openralph ${phase}${replayArgs ? ` ${replayArgs}` : ""} --no-docker`
|
|
207
225
|
}
|
|
208
226
|
|
|
209
227
|
function commandOutput(result: CommandResult): string {
|