@boldblackai/harness 1.9.13 → 1.10.0

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.
Files changed (3) hide show
  1. package/README.md +25 -9
  2. package/bin/harness.js +129 -29
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Harness conveniently wraps Docker around three open-source coding agents — [`pi`](https://pi.dev/), [`opencode`](https://opencode.ai),
6
6
  and [`hermes`](https://github.com/NousResearch/hermes-agent) — so you can point one at a directory (or file) without giving it access to your entire machine.
7
7
 
8
- > **Documentation:** [boldblackai.github.io/harness](https://boldblackai.github.io/harness/)
8
+ > **Documentation:** [harness.boldblack.ai/docs](https://harness.boldblack.ai/docs/)
9
9
 
10
10
  ## Features
11
11
 
@@ -20,7 +20,7 @@ and [`hermes`](https://github.com/NousResearch/hermes-agent) — so you can poin
20
20
 
21
21
  ## Quickstart
22
22
 
23
- A container runtime is required. By default harness uses [Docker](https://www.docker.com); on macOS 26 / Apple Silicon you can also use Apple's native [`container`](https://github.com/apple/container) CLI — see [Container runtime](#container-runtime). With the default runtime and LM Studio locally:
23
+ A container runtime is required. By default harness uses [Docker](https://www.docker.com); on macOS 26 / Apple Silicon, Apple's native [`container`](https://github.com/apple/container) CLI is preferred automatically if installed — see [Container runtime](#container-runtime). With the default runtime and LM Studio locally:
24
24
 
25
25
  ```bash
26
26
  lms daemon up
@@ -188,7 +188,7 @@ Each run starts the container with:
188
188
 
189
189
  Running harness from your home directory is blocked by default, since that would mount all of `$HOME` into the container — exposing dotfiles, credentials, and SSH keys to the agent and giving it a noisy, unfocused workspace. If the resolved working directory equals your home, harness exits with an error. Pass `--mount-entire-home` to opt in for the rare case where mounting all of `$HOME` is genuinely intended. `--file` mode is unaffected (it mounts a single file, not the working directory).
190
190
 
191
- These hardening flags are docker-specific. Under `HARNESS_CONTAINER_RUNTIME=apple`, `--security-opt` is not applied (apple/container workloads are microVMs with their own guest kernel, so the seccomp profile's host-kernel role is subsumed by the VM boundary); capability restrictions remain. See [Container runtime](#container-runtime).
191
+ These hardening flags are docker-specific. When running under Apple's `container` CLI (auto-detected on macOS 26 / Apple Silicon), `--security-opt` is not applied (apple/container workloads are microVMs with their own guest kernel, so the seccomp profile's host-kernel role is subsumed by the VM boundary); capability restrictions remain. See [Container runtime](#container-runtime).
192
192
 
193
193
  ### Image verification
194
194
 
@@ -228,11 +228,12 @@ If an old `.harness/` directory exists in your working directory, harness will e
228
228
  | Flag | Alias | Description |
229
229
  |---------------|-------|-------------|
230
230
  | `--prompt` | `-p` | Pass a prompt directly to the agent |
231
- | `--env-file` | `-e` | Load environment variables into the container |
231
+ | `--env-file` | `-e` | Load environment variables into the container; may be repeated |
232
232
  | `--file` | `-f` | Mount a single file instead of the current directory |
233
233
  | `--model` | `-m` | Override the model used by the agent |
234
234
  | `--agent` | `-a` | Select agent: `pi`, `opencode`, `hermes` (default: `pi`) |
235
235
  | `--volumes` | `-v` | Additional volume mount (`host:container[:opts]`); may be repeated |
236
+ | `--port` | | Publish a container port to the host (`[host-ip:]host-port:container-port[/protocol]`); may be repeated |
236
237
  | `--no-verify` | | Skip cosign signature and provenance verification |
237
238
  | `--no-skills` | | Disable mounting user skills directories (`~/.agents/skills`, `~/.claude/skills`) |
238
239
  | `--no-context-files` | `-nc` | Disable mounting global context files (`~/.agents/AGENTS.md`, `~/.claude/CLAUDE.md`) |
@@ -246,27 +247,34 @@ If an old `.harness/` directory exists in your working directory, harness will e
246
247
  | Variable | Description |
247
248
  |-----------------------------|-------------|
248
249
  | `HARNESS_IMAGE_TAG` | Override the Docker image tag (defaults to the package version). Setting this implies `--no-verify`. |
249
- | `HARNESS_CONTAINER_RUNTIME` | Container runtime to use: `docker` (default) or `apple` (Apple's [`container`](https://github.com/apple/container) CLI). |
250
+ | `HARNESS_CONTAINER_RUNTIME` | Container runtime: `auto` (default — on macOS, prefers Apple's `container` CLI if on PATH; docker everywhere else), `docker` (force docker), or `apple` (deprecated explicit alias; warns). |
250
251
  | `XDG_DATA_HOME` | Override the base directory for persistence data (defaults to `~/.local/share`). |
251
252
  | `XDG_CACHE_HOME` | Override the base directory for the cosign cache (defaults to `~/.cache`). |
252
253
 
253
254
  #### Container runtime
254
255
 
255
- By default harness runs images with `docker`. On macOS 26 / Apple Silicon you can opt into Apple's native [`container`](https://github.com/apple/container) CLI (v1.0.0+) instead, which runs OCI images as lightweight Linux microVMs:
256
+ By default harness auto-detects the container runtime: on macOS, if Apple's native [`container`](https://github.com/apple/container) CLI (v1.0.0+) is on PATH, it is preferred; on every other platform docker is used. Auto-detection is gated to macOS because apple/container ships for macOS only — a binary named `container` on a Linux PATH is an unrelated tool and is ignored. No configuration is needed.
256
257
 
257
258
  ```bash
258
259
  brew install container # install Apple's container CLI (v1.0.0+)
259
260
  container system start # one-time: start the container system service
260
261
  container system kernel set --recommended --arch arm64 # one-time on Apple Silicon (required before first run)
261
- export HARNESS_CONTAINER_RUNTIME=apple
262
262
  harness -p "write me a fizzbuzz in Go"
263
263
  ```
264
264
 
265
265
  On arm64 Macs, `container system kernel set --recommended` is required — without it the first `harness` run fails with `default kernel not configured for architecture arm64`. See [apple/container](https://github.com/apple/container) for details.
266
266
 
267
- The value is **named, not boolean** (`apple` or `docker`, case-insensitive); any other value is a hard error. harness never auto-detects the runtime — you must opt in. Image verification (cosign + SLSA provenance) works identically under both runtimes; the verified-digest cache is keyed by digest, so a digest verified under one runtime is a cache hit under the other.
267
+ To force docker even when `container` is available, set:
268
268
 
269
- **Security note.** Under `=apple`, harness does not apply the `--security-opt no-new-privileges` and `--security-opt seccomp=...` flags it uses under docker, because `apple/container` has no `--security-opt` option. This is not a security regression: each apple/container workload is a microVM with its own ephemeral guest kernel (Apple Virtualization framework), so the `block-af-alg.json` profile's host-kernel role — blocking `socket(AF_ALG)` — is subsumed by the VM boundary itself (hardware-assisted isolation, strictly stronger than a syscall filter). Capability restrictions (`--cap-drop=ALL --cap-add=NET_RAW`) **are** supported and stay on. Only `ro`/`readonly` is honored for volume options under the apple path (SELinux relabel flags like `:Z` are meaningless under macOS virtiofs).
269
+ ```bash
270
+ export HARNESS_CONTAINER_RUNTIME=docker
271
+ ```
272
+
273
+ `HARNESS_CONTAINER_RUNTIME=apple` (the pre-auto-detect opt-in) still works but is deprecated: it selects the apple runtime explicitly, prints a deprecation warning, and will be removed in a future release.
274
+
275
+ Image verification (cosign + SLSA provenance) works identically under both runtimes; the verified-digest cache is keyed by digest, so a digest verified under one runtime is a cache hit under the other.
276
+
277
+ **Security note.** When running under Apple's `container` CLI, harness does not apply the `--security-opt no-new-privileges` and `--security-opt seccomp=...` flags it uses under docker, because `apple/container` has no `--security-opt` option. This is not a security regression: each apple/container workload is a microVM with its own ephemeral guest kernel (Apple Virtualization framework), so the `block-af-alg.json` profile's host-kernel role — blocking `socket(AF_ALG)` — is subsumed by the VM boundary itself (hardware-assisted isolation, strictly stronger than a syscall filter). Capability restrictions (`--cap-drop=ALL --cap-add=NET_RAW`) **are** supported and stay on. Only `ro`/`readonly` is honored for volume options under the apple path (SELinux relabel flags like `:Z` are meaningless under macOS virtiofs).
270
278
 
271
279
  **Optional tuning — resource limits.** Apple's container CLI reads defaults from `~/.config/container/config.toml`. Create this file to control CPU and memory allocation for all containers (see [container-system-config.md](https://github.com/apple/container/blob/main/docs/container-system-config.md) for the full schema):
272
280
 
@@ -277,6 +285,14 @@ cpus = 8
277
285
  memory = "4g"
278
286
  ```
279
287
 
288
+ **Container → host (`host.docker.internal`).** Docker Desktop provides `host.docker.internal` automatically; Apple's `container` CLI does not. Local-mode agents (pi, opencode, hermes without `-e`) reach LM Studio and other host services via that hostname. One-time setup on Apple Silicon (requires administrator):
289
+
290
+ ```bash
291
+ sudo container system dns create host.docker.internal --localhost 203.0.113.113
292
+ ```
293
+
294
+ Harness prints a reminder on `HARNESS_CONTAINER_RUNTIME=apple` runs if this mapping is missing. See [apple/container — access a host service](https://github.com/apple/container/blob/main/docs/how-to.md#access-a-host-service-from-a-container).
295
+
280
296
  ### Agent-specific behavior
281
297
 
282
298
  - **pi** — `-m` is passed straight to the binary as `--model`.
package/bin/harness.js CHANGED
@@ -53,6 +53,7 @@ class DockerRuntime {
53
53
  ...input.envArgs,
54
54
  ...input.volumeArgs,
55
55
  ...input.userVolumeArgs,
56
+ ...input.portArgs,
56
57
  "-w",
57
58
  input.workdir,
58
59
  input.image,
@@ -60,10 +61,28 @@ class DockerRuntime {
60
61
  ];
61
62
  }
62
63
  ensureReady() {
63
- // docker is the default; assume present. (A missing docker surfaces as a
64
+ // docker is the fallback; assume present. (A missing docker surfaces as a
64
65
  // clear spawn ENOENT at run time, same as pre-runtime-abstraction behavior.)
65
66
  }
66
67
  }
68
+ const HOST_DOCKER_INTERNAL = "host.docker.internal";
69
+ // Documentation-range IP apple/container uses to route a custom DNS name to the
70
+ // host's localhost. See apple/container how-to: "Access a host service from a
71
+ // container".
72
+ const APPLE_HOST_LOCALHOST_IP = "203.0.113.113";
73
+ function appleHostDockerInternalDnsConfigured() {
74
+ try {
75
+ const out = (0, node_child_process_1.execFileSync)("container", ["system", "dns", "list"], {
76
+ stdio: ["ignore", "pipe", "ignore"],
77
+ timeout: 5000,
78
+ }).toString();
79
+ return out.includes(HOST_DOCKER_INTERNAL);
80
+ }
81
+ catch {
82
+ // If we cannot inspect DNS config, do not block the run.
83
+ return true;
84
+ }
85
+ }
67
86
  class AppleContainerRuntime {
68
87
  binary() {
69
88
  return "container";
@@ -130,6 +149,7 @@ class AppleContainerRuntime {
130
149
  ...input.envArgs,
131
150
  ...input.volumeArgs,
132
151
  ...input.userVolumeArgs,
152
+ ...input.portArgs,
133
153
  "-w",
134
154
  input.workdir,
135
155
  input.image,
@@ -137,38 +157,75 @@ class AppleContainerRuntime {
137
157
  ];
138
158
  }
139
159
  ensureReady() {
160
+ // selectRuntime() already probed `container --version` (memoized); a false
161
+ // here means the probe failed there too — same evidence, one exec.
162
+ if (!appleContainerAvailable()) {
163
+ console.error("harness: the `container` CLI failed its version probe (Apple container, v1.0.0+). Install from https://github.com/apple/container/releases and run `container system start`, or set HARNESS_CONTAINER_RUNTIME=docker to use docker instead.");
164
+ process.exit(1);
165
+ }
166
+ if (!appleHostDockerInternalDnsConfigured()) {
167
+ console.error(`harness: ${HOST_DOCKER_INTERNAL} is not configured for Apple's container runtime.\nLocal services on the Mac (e.g. LM Studio on :1234) will not be reachable from the container.\nOne-time fix (requires administrator):\n sudo container system dns create ${HOST_DOCKER_INTERNAL} --localhost ${APPLE_HOST_LOCALHOST_IP}\nSee https://github.com/apple/container/blob/main/docs/how-to.md#access-a-host-service-from-a-container`);
168
+ }
169
+ }
170
+ }
171
+ function selectRuntime() {
172
+ const raw = (process.env.HARNESS_CONTAINER_RUNTIME ?? "").toLowerCase();
173
+ if (raw === "docker") {
174
+ return new DockerRuntime();
175
+ }
176
+ if (raw === "apple") {
177
+ // Deprecated: the apple runtime is now auto-detected on macOS. Keep the
178
+ // value working (with a warning) so existing configs don't hard-fail.
179
+ console.error('harness: HARNESS_CONTAINER_RUNTIME=apple is deprecated (the apple runtime is now auto-detected on macOS); unset the variable, or use "auto" or "docker".');
180
+ return new AppleContainerRuntime();
181
+ }
182
+ if (raw !== "" && raw !== "auto") {
183
+ console.error(`harness: unknown HARNESS_CONTAINER_RUNTIME="${raw}". Valid values: auto (default), docker, apple (deprecated) — or unset for auto-detect.`);
184
+ process.exit(1);
185
+ }
186
+ // Auto-detect: prefer Apple's container CLI when it actually executes —
187
+ // but only on macOS. apple/container ships for macOS only, so on any other
188
+ // platform a binary named `container` is an unrelated tool and docker stays
189
+ // default. Probing `--version` (not just a PATH lookup) proves the binary
190
+ // runs at all; broken installs, quarantine attributes, and wrong-arch
191
+ // builds all fail here, and execution is what selection depends on.
192
+ if (process.platform === "darwin" && appleContainerAvailable()) {
193
+ return new AppleContainerRuntime();
194
+ }
195
+ return new DockerRuntime();
196
+ }
197
+ /**
198
+ * Whether Apple's `container` CLI exists and executes. Reuses the same
199
+ * `--version` probe `AppleContainerRuntime.ensureReady()` runs, which is
200
+ * strictly stronger evidence than a PATH lookup. The result is memoized for
201
+ * the process lifetime so `selectRuntime()` and `ensureReady()` share one
202
+ * probe instead of running it twice; it is never persisted across runs, since
203
+ * the CLI's install state can change between invocations.
204
+ */
205
+ let appleContainerAvailableMemo = null;
206
+ function appleContainerAvailable() {
207
+ if (appleContainerAvailableMemo === null) {
140
208
  try {
141
209
  (0, node_child_process_1.execFileSync)("container", ["--version"], {
142
- stdio: ["ignore", "ignore", "ignore"],
210
+ stdio: "ignore",
143
211
  timeout: 5000,
144
212
  });
213
+ appleContainerAvailableMemo = true;
145
214
  }
146
215
  catch {
147
- console.error("harness: HARNESS_CONTAINER_RUNTIME=apple requires the `container` CLI (Apple container, v1.0.0+). Install from https://github.com/apple/container/releases and run `container system start`, or unset HARNESS_CONTAINER_RUNTIME to use docker.");
148
- process.exit(1);
216
+ appleContainerAvailableMemo = false;
149
217
  }
150
218
  }
151
- }
152
- function selectRuntime() {
153
- const raw = (process.env.HARNESS_CONTAINER_RUNTIME ?? "docker").toLowerCase();
154
- switch (raw) {
155
- case "docker":
156
- return new DockerRuntime();
157
- case "apple":
158
- return new AppleContainerRuntime();
159
- default:
160
- console.error(`harness: unknown HARNESS_CONTAINER_RUNTIME="${raw}". Valid values: apple, docker (or unset for docker).`);
161
- process.exit(1);
162
- }
219
+ return appleContainerAvailableMemo;
163
220
  }
164
221
  class PiAdapter {
165
- buildCommand({ prompt, model, envFilePath }) {
222
+ buildCommand({ prompt, model, envFilePaths }) {
166
223
  // In local mode (no env file), pass --provider ollama so pi routes
167
224
  // the model to the local LM Studio provider. Without this, model names
168
225
  // containing slashes (e.g. HuggingFace IDs like "qwen/qwen3.5-9b") are
169
226
  // misinterpreted as provider/model format, causing pi to silently ignore
170
227
  // --model and fall back to a default that may require cloud credentials.
171
- const providerArgs = !envFilePath && model ? ["--provider", "ollama"] : [];
228
+ const providerArgs = envFilePaths.length === 0 && model ? ["--provider", "ollama"] : [];
172
229
  const modelArgs = model ? ["--model", model] : [];
173
230
  if (prompt !== null) {
174
231
  return ["pi", "-p", prompt, ...providerArgs, ...modelArgs];
@@ -362,11 +419,12 @@ const USAGE = `Usage: harness [options]
362
419
 
363
420
  Options:
364
421
  -p, --prompt <text> Pass a prompt directly to the coding agent
365
- -e, --env-file <file> Load environment variables from a file into the container
422
+ -e, --env-file <file> Load environment variables from a file into the container; may be repeated
366
423
  -f, --file <file> Mount a single file into the container instead of the current directory
367
424
  -m, --model <model> Override the model used by the agent
368
425
  -a, --agent <name> Select the coding agent adapter: pi, opencode, hermes (default: pi)
369
426
  -v, --volumes <spec> Additional volume mount (host:container[:opts]); may be repeated
427
+ --port <spec> Publish a container port to the host ([host-ip:]host-port:container-port[/protocol]); may be repeated
370
428
  --no-verify Skip cosign image signature and provenance verification
371
429
  --no-skills Disable mounting user skills directories (~/.agents/skills, ~/.claude/skills)
372
430
  --no-context-files Disable mounting global context files (~/.agents/AGENTS.md, ~/.claude/CLAUDE.md); alias -nc
@@ -378,7 +436,7 @@ Options:
378
436
  Environment variables:
379
437
  HARNESS_IMAGE_TAG Override the Docker image tag (defaults to package version)
380
438
  HARNESS_REGISTRY Override the container registry (defaults to ghcr.io/boldblackai/harness)
381
- HARNESS_CONTAINER_RUNTIME Container runtime to use: docker (default) or apple (Apple container CLI)
439
+ HARNESS_CONTAINER_RUNTIME Container runtime: auto (default; prefers Apple container on macOS), docker, apple (deprecated)
382
440
  XDG_DATA_HOME Override the base directory for persistence data (defaults to ~/.local/share)
383
441
  XDG_CACHE_HOME Override the base directory for cosign cache (defaults to ~/.cache)
384
442
 
@@ -424,6 +482,7 @@ const MINIMIST_OPTS = {
424
482
  "agent",
425
483
  "a",
426
484
  "volumes",
485
+ "port",
427
486
  ],
428
487
  alias: {
429
488
  e: "env-file",
@@ -468,7 +527,11 @@ const noSkills = argv.skills === false;
468
527
  const noContextFiles = argv["context-files"] === false;
469
528
  const mountEntireHome = argv["mount-entire-home"] === true;
470
529
  const localMode = argv.local;
471
- const envFilePath = argv["env-file"] || null;
530
+ const envFilePaths = Array.isArray(argv["env-file"])
531
+ ? argv["env-file"]
532
+ : argv["env-file"]
533
+ ? [argv["env-file"]]
534
+ : [];
472
535
  const fileArg = argv.file || null;
473
536
  const promptArg = argv.prompt || null;
474
537
  const modelArg = argv.model || null;
@@ -481,9 +544,11 @@ const agentName = (() => {
481
544
  }
482
545
  return name;
483
546
  })();
484
- if (envFilePath && !node_fs_1.default.existsSync(envFilePath)) {
485
- console.error(`harness: env file not found: ${envFilePath}`);
486
- process.exit(1);
547
+ for (const ep of envFilePaths) {
548
+ if (!node_fs_1.default.existsSync(ep)) {
549
+ console.error(`harness: env file not found: ${ep}`);
550
+ process.exit(1);
551
+ }
487
552
  }
488
553
  if (fileArg && !node_fs_1.default.existsSync(fileArg)) {
489
554
  console.error(`harness: file not found: ${fileArg}`);
@@ -522,6 +587,33 @@ for (const spec of volumeArgList) {
522
587
  process.exit(1);
523
588
  }
524
589
  }
590
+ // Publish specs use the shared docker/apple-container syntax
591
+ // [host-ip:]host-port:container-port[/protocol]. Validate up front so a
592
+ // typo fails fast with a clear message instead of an opaque runtime error
593
+ // after image verification/pulling.
594
+ const PORT_SPEC_REGEXP = /^(?:(?:\d{1,3}(?:\.\d{1,3}){3}|\[[0-9a-fA-F:.]+\]):)?(\d{1,5}):(\d{1,5})(?:\/(tcp|udp|sctp))?$/;
595
+ function isValidPortSpec(spec) {
596
+ const match = spec.match(PORT_SPEC_REGEXP);
597
+ if (!match) {
598
+ return false;
599
+ }
600
+ const portInRange = (p) => {
601
+ const n = Number.parseInt(p, 10);
602
+ return n >= 1 && n <= 65535;
603
+ };
604
+ return portInRange(match[1]) && portInRange(match[2]);
605
+ }
606
+ const portArgList = Array.isArray(argv.port)
607
+ ? argv.port
608
+ : argv.port
609
+ ? [argv.port]
610
+ : [];
611
+ for (const spec of portArgList) {
612
+ if (!isValidPortSpec(spec)) {
613
+ console.error(`harness: invalid port spec "${spec}" (expected [host-ip:]host-port:container-port[/protocol], e.g. 8080:3000)`);
614
+ process.exit(1);
615
+ }
616
+ }
525
617
  async function run(prompt) {
526
618
  const runtime = selectRuntime();
527
619
  runtime.ensureReady();
@@ -534,14 +626,15 @@ async function run(prompt) {
534
626
  await verifyImage(runtime, image);
535
627
  }
536
628
  }
537
- const envFileArgs = envFilePath
538
- ? ["--env-file", node_path_1.default.resolve(envFilePath)]
539
- : [];
629
+ const envFileArgs = envFilePaths.flatMap((f) => [
630
+ "--env-file",
631
+ node_path_1.default.resolve(f),
632
+ ]);
540
633
  // Cloud mode: -e without --local signals entrypoints to skip local/defaults
541
634
  // and let agents auto-detect providers from env vars in the file.
542
- const cloudModeEnv = envFilePath && !localMode ? ["-e", "HARNESS_CLOUD_MODE=1"] : [];
635
+ const cloudModeEnv = envFilePaths.length > 0 && !localMode ? ["-e", "HARNESS_CLOUD_MODE=1"] : [];
543
636
  const adapter = ADAPTERS[agentName];
544
- const adapterOptions = { prompt, model: modelArg, envFilePath };
637
+ const adapterOptions = { prompt, model: modelArg, envFilePaths };
545
638
  const containerCmd = adapter.buildCommand(adapterOptions);
546
639
  const adapterDockerArgs = adapter.extraDockerArgs?.(adapterOptions) ?? [];
547
640
  const interactive = process.stdin.isTTY;
@@ -629,12 +722,19 @@ async function run(prompt) {
629
722
  for (const spec of volumeArgList) {
630
723
  userVolumeArgs.push("-v", `${node_path_1.default.resolve(spec.split(":")[0])}:${spec.split(":").slice(1).join(":")}`);
631
724
  }
725
+ // docker -p and apple/container --publish share the spec syntax, so the
726
+ // flags are runtime-agnostic (unlike caps/tty handling).
727
+ const portArgs = [];
728
+ for (const spec of portArgList) {
729
+ portArgs.push("-p", spec);
730
+ }
632
731
  const args = runtime.runArgs({
633
732
  interactive,
634
733
  envFileArgs,
635
734
  envArgs: [...cloudModeEnv, ...adapterDockerArgs],
636
735
  volumeArgs,
637
736
  userVolumeArgs,
737
+ portArgs,
638
738
  workdir: "/workspace",
639
739
  image,
640
740
  containerCmd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boldblackai/harness",
3
- "version": "1.9.13",
3
+ "version": "1.10.0",
4
4
  "description": "Portable environment for running coding agents in a container",
5
5
  "bin": {
6
6
  "harness": "bin/harness.js"