Files
hyperframes/packages/cli
James RussoandClaude Fable 5 0766eb8144 feat(cli): detect Gemini managed-agent sandbox in detectAgentRuntime (#1294)
* feat(cli): detect Gemini managed-agent sandbox in detectAgentRuntime

Add `gemini_managed_agent` to the AgentRuntime union and a dedicated
isGeminiManagedAgent() detector. Empirical signal pair (from live-sandbox
introspection by gemini-agent, env_id b9db4e56, 2026-06-09):

  existsSync('/.agents/AGENTS.md')  AND  isGVisor()

The conjunction is what makes the rule safe:

  - `/.agents/AGENTS.md` excludes generic gVisor surfaces (GKE Sandbox,
    Cloud Run gen2) that don't mount the managed-agent layout.
  - The gVisor kernel check excludes a dev box that happens to have a
    stray `/.agents/` directory.

Implementation notes:

  - Filesystem-based check runs ahead of the env-var-only VENDOR_RULES
    loop. VENDOR_RULES is documented as "Only checks for the EXISTENCE
    of well-known env vars — never reads their values"; the Gemini
    signal is filesystem + kernel, not env, so it gets a dedicated
    branch rather than shoehorning into the rule list.

  - GEMINI_API_KEY is deliberately NOT keyed on — it's user-settable on
    any host. The filesystem + kernel pair is the actually-distinctive
    signal.

  - Reuses the existing isGVisor() helper for the kernel half of the
    conjunction; no duplication.

Tests (4 new, vitest):

  - Positive: /.agents/AGENTS.md + 4.19.0-gvisor → gemini_managed_agent
  - Negative: gVisor alone (no /.agents/) → null (generic gVisor surface)
  - Negative: /.agents/AGENTS.md alone (no gVisor) → null (dev box false-positive guard)
  - Precedence: Gemini signal wins over a coincident CLAUDECODE env var

Empirical caveat: signal was gathered from a single sandbox. Re-confirming
across additional sandbox spins is a follow-up; the rule is conservative
enough (conjunction of two independent signals) that a single-spin
false-positive is unlikely, but a single-spin variance bug (e.g. some
sandbox flavors omitting one of the two markers) would surface as
under-detection rather than over-detection.

Source for signals: introspection write-up at
/tmp/gemini-sandbox-detection-signals.md (gemini-agent, 2026-06-09).

* docs(cli): reframe Gemini-managed-agent detection rationale (load-bearing vs guard)

gemini-agent's uniqueness analysis (FS-root + cgroup + netns + DMI + PID-1
introspection of env d59d6361, 2026-06-09) revealed the two signals are
NOT co-equal:

- /.agents/AGENTS.md is the uniqueness anchor — definitionally a
  managed-agent artifact, injected per-run by the platform, mtime
  tracks the interaction. Nothing in the generic Google-Cloud-on-gVisor
  universe (Cloud Run gen2, GKE Sandbox, Fly.io) mounts /.agents/.
- isGVisor() is a guard, not a second uniqueness signal. gVisor itself
  is shared with GKE Sandbox + Cloud Run gen2 — its real job here is
  ruling out a stray user-created /.agents/AGENTS.md on a non-sandbox
  host.

The original 3-spin work proved *stability* (signals consistent across
sandbox spins). This pass adds *uniqueness* — confirming the signals
discriminate Antigravity from the broader gVisor universe, not just
that they're reliably present. Stability ≠ uniqueness; both are
required for a correct detection rule.

Code unchanged (the AND-gate is sound). Docstring reframed so a future
reader doesn't mistake the conjunction for two independent uniqueness
signals. Also enumerated the markers NOT keyed on (with reasons), so
future contributors don't reach for them by naming inference.

Source: gemini-agent uniqueness analysis write-up.

* fix(cli): key Gemini managed-agent detection on /.agents/ mount, not optional AGENTS.md

The detector keyed on existsSync('/.agents/AGENTS.md'), but Google's Managed
Agents docs are explicit that AGENTS.md is OPTIONAL: an agent may declare its
instructions inline via system_instruction in agent.yaml and ship no AGENTS.md
file ("system_instruction and AGENTS.md are additive; both apply when present").
The platform auto-discovers the agent under the /.agents/ directory; skills
mount at /.agents/skills/ and AGENTS.md at /.agents/AGENTS.md only when shipped.

Keying on the file generalized only to templates that happen to bundle an
AGENTS.md (like HeyGen's own gemini-agent and Thor's reference). A managed agent
defined with inline instructions or a skills-only definition was a silent
false-negative. All three prior verification spins used our own AGENTS.md-bearing
template, so the gap was never exercised.

Broaden to the /.agents/ directory mount (still gVisor-guarded — false-positive
surface is unchanged) so skills-only and inline-instruction agents are detected.
Adds a regression test for the skills-but-no-AGENTS.md case. Documents the one
residual gap (pure inline-only, no skills/no AGENTS.md) that needs an empirical
spin to confirm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(cli): tighten /.agents/ to a directory check + sync agent_runtime docs

Self-review follow-ups (no behavior change for real managed agents):

- isGeminiManagedAgent now requires statSync("/.agents").isDirectory() rather
  than existsSync("/.agents"), matching the documented "directory mount"
  contract. existsSync matched any entry (a stray file/symlink named /.agents),
  widening the gVisor-gated false-positive surface beyond what the comment
  claimed. Tests now mock statSync accordingly (and drop a dead /.agents/skills
  mock clause the code never read).
- system.ts: the agent_runtime doc comment hard-coded the vendor list and said
  "detected by env-var existence only" — both stale once a filesystem/kernel
  detector (gemini_managed_agent) exists. Point at the AgentRuntime union and
  note the filesystem-marker case instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 17:05:50 -07:00
..
2026-06-10 23:26:13 +00:00

hyperframes

CLI for creating, previewing, and rendering HTML video compositions.

Install

npm install -g hyperframes

Or use directly with npx:

npx hyperframes <command>

Requirements: Node.js >= 22, FFmpeg

Commands

init

Scaffold a new Hyperframes project from a template:

npx hyperframes init my-video
cd my-video

preview

Start the live preview studio in your browser:

npx hyperframes preview
# Studio running at http://localhost:3002

npx hyperframes preview --port 4567

render

Render a composition to MP4:

npx hyperframes render ./my-composition.html -o output.mp4

lint

Validate your Hyperframes HTML:

npx hyperframes lint ./my-composition
npx hyperframes lint ./my-composition --json      # JSON output for CI/tooling
npx hyperframes lint ./my-composition --verbose   # Include info-level findings

By default only errors and warnings are shown. Use --verbose to also display informational findings (e.g., external script dependency notices). Use --json for machine-readable output with errorCount, warningCount, infoCount, and a findings array.

compositions

List compositions found in the current project:

npx hyperframes compositions

benchmark

Run rendering benchmarks:

npx hyperframes benchmark ./my-composition.html

doctor

Check your environment for required dependencies (Chrome, FFmpeg, Node.js):

npx hyperframes doctor

browser

Manage the bundled Chrome/Chromium installation:

npx hyperframes browser

info

Print version and environment info:

npx hyperframes info

docs

Open the documentation in your browser:

npx hyperframes docs

upgrade

Check for updates and show upgrade instructions:

npx hyperframes upgrade
npx hyperframes upgrade --check --json  # machine-readable for agents

Documentation

Full documentation: hyperframes.heygen.com/packages/cli