@kybernesis/create 0.12.3 → 0.13.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.
package/dist/doctor.js CHANGED
@@ -275,6 +275,32 @@ export async function doctor() {
275
275
  else {
276
276
  add("fail", `self-hosted: ${shortQueueTimeouts.join(" and ")} left at the 30s default`, "one queue delivery holds a connection open for the entire turn, so any turn slower than the timeout is redelivered and its steps re-run — the agent answers the same question twice, with two different answers, and nothing reports an error. Set both to 900000 in .env.local and restart the server");
277
277
  }
278
+ /**
279
+ * Instructions that name a tool the agent does not have.
280
+ *
281
+ * `deliver` mounts with the engineer layer, which is mounted on the builder
282
+ * subagent — so an agent whose ROOT is told to hand over files (by its own
283
+ * instructions, or by our playbook, which says to) promises a file it
284
+ * cannot send. It cannot see the mismatch either: it writes the contents to
285
+ * a memory note, or apologises without a cause, and the delivery
286
+ * infrastructure passes every check while nobody can receive anything.
287
+ */
288
+ const rootDeliver = existsSync(join(cwd, "agent/tools/deliver.ts"));
289
+ const instructionsMentionDeliver = (() => {
290
+ try {
291
+ const dir = join(cwd, "agent/instructions");
292
+ return readdirSync(dir).some((file) => readFileSync(join(dir, file), "utf8").includes("deliver"));
293
+ }
294
+ catch {
295
+ return false;
296
+ }
297
+ })();
298
+ if (instructionsMentionDeliver && !rootDeliver) {
299
+ add("fail", "instructions tell this agent to deliver files, but the root has no deliver tool", 'add agent/tools/deliver.ts: export { deliver as default } from "@kybernesis/engineer/tools" — the engineer layer mounts it on the builder subagent only');
300
+ }
301
+ else if (rootDeliver) {
302
+ add("pass", "the agent that talks to people can also hand them a file");
303
+ }
278
304
  // The exe VM sandbox backend needs a credential that cannot be scoped.
279
305
  // Surface the blast radius here, where it is still cheap to change course.
280
306
  const sandboxFile = join(cwd, "agent/sandbox/sandbox.ts");
@@ -350,7 +376,11 @@ export async function doctor() {
350
376
  add("fail", "engineer subagent has NO sandbox of its own", "subagents do not inherit the root sandbox — add agent/subagents/builder/sandbox/sandbox.ts or the vision loop cannot run");
351
377
  }
352
378
  if (existsSync(join(builderDir, "extensions/engineer.ts"))) {
353
- add("pass", "engineer mounted locally on the subagent (root keeps no shell)");
379
+ // Not "the root keeps no shell": every eve agent has a sandbox with bash,
380
+ // read_file, write_file, glob and grep. What the local mount withholds is
381
+ // the build loop and any shell ON THE HOST. This sentence is one people
382
+ // reason about security boundaries from, so it says the true thing.
383
+ add("pass", "engineer mounted locally on the subagent (root gets no host shell, no build loop)");
354
384
  }
355
385
  else {
356
386
  add("warn", "engineer extension not mounted on the subagent", "agent/subagents/builder/extensions/engineer.ts");
package/dist/templates.js CHANGED
@@ -513,18 +513,39 @@ export default defineAgent({
513
513
  "Builds and runs software: scaffolds projects, writes code, installs dependencies, runs builds and dev servers, and visually verifies rendered pages. Use when the user asks for something to be BUILT, prototyped, deployed, or fixed in code — not for questions, planning, or scheduling.",
514
514
  model: ${JSON.stringify(model)},
515
515
  });
516
+ `,
517
+ },
518
+ {
519
+ path: "agent/tools/deliver.ts",
520
+ content: `// Handing a file to the person you are talking to.
521
+ //
522
+ // The engineer layer mounts on \`builder\`, so building stays there — but
523
+ // DELIVERING is not building. It reads one file from this agent's own sandbox
524
+ // and copies it to storage, runs no commands and writes nothing back, and the
525
+ // agent that needs it is the one talking to the user.
526
+ //
527
+ // Without this the root is told (by its instructions, and by our own playbook)
528
+ // to deliver files and has no such tool. It cannot detect the mismatch, so it
529
+ // promises a file and then quietly puts the contents somewhere nobody can
530
+ // reach — a memory note, or an apology with no cause given.
531
+ export { deliver as default } from "@kybernesis/engineer/tools";
516
532
  `,
517
533
  },
518
534
  {
519
535
  path: "agent/subagents/builder/extensions/engineer.ts",
520
536
  content: `// Engineer layer mounted LOCALLY on this subagent (eve >=0.30): screenshot,
521
537
  // deliver, and the trade-school skills belong to \`builder\` alone, so the root
522
- // agent has no shell.
538
+ // gets no shell ON THE HOST and none of the build loop.
539
+ //
540
+ // Not "the root has no shell" — every eve agent has a sandbox with bash,
541
+ // read_file, write_file, glob and grep, and this app builds two templates
542
+ // (root and builder). The root's shell is its own container. The distinction
543
+ // that matters is host access, and the old wording blurred exactly the line
544
+ // people read this comment to understand.
523
545
  //
524
546
  // The root DOES get a browser and GitHub tools — the engineer layer installs
525
547
  // extension/agent-browser and extension/github-tools at the root, deliberately,
526
548
  // because reading a page is not the same blast radius as running a command.
527
- // This comment used to claim otherwise, which is worse than saying nothing.
528
549
  export { default } from "@kybernesis/engineer";
529
550
  `,
530
551
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kybernesis/create",
3
- "version": "0.12.3",
3
+ "version": "0.13.0",
4
4
  "description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent — plus doctor and upgrade.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -2052,9 +2052,23 @@ tool. Reads went from unreliable to deterministic with about sixty lines.
2052
2052
  ### 11.6 The engineer layer, self-hosted
2053
2053
 
2054
2054
  `--engineer` scaffolds a **builder subagent** that owns the build capability, so
2055
- the root agent never gets a shell. It comes with the full production loop
2056
- workshop sandbox, Playwright, screenshots, visual verification, delivery — not a
2057
- reduced version of the Vercel one.
2055
+ the root agent gets **no shell on the host and no build loop**. It comes with the
2056
+ full production loop — workshop sandbox, Playwright, screenshots, visual
2057
+ verification, delivery — not a reduced version of the Vercel one.
2058
+
2059
+ > Say it that way rather than "the root never gets a shell". Every eve agent has
2060
+ > a sandbox with `bash`, `read_file`, `write_file`, `glob` and `grep`, and an
2061
+ > `--engineer` app builds two templates. The root's shell is its own container.
2062
+ > The line that matters is host access, and the shorter phrasing blurs exactly
2063
+ > the boundary people quote this passage to explain.
2064
+
2065
+ **Delivery belongs to the root as well.** The engineer layer mounts on `builder`,
2066
+ but the agent that talks to people is the one asked for files — and delivering
2067
+ reads one file and copies it, which is not the blast radius that justified
2068
+ keeping the build loop away from the root. `kyb init --engineer` now scaffolds
2069
+ `agent/tools/deliver.ts` for exactly this. An agent instructed to hand over files
2070
+ without that mount cannot tell it is missing: it writes the contents to a memory
2071
+ note and reports success.
2058
2072
 
2059
2073
  - **Subagents own their sandbox; they do NOT inherit the root's.** A builder
2060
2074
  without its own `sandbox/sandbox.ts` gets a bare template and every screenshot