<permissions instructions>
Filesystem sandboxing defines which files can be read or written. `sandbox_mode` is `danger-full-access`: No filesystem sandboxing - all commands are permitted. Network access is enabled.
Approval policy is currently never. Do not provide the `sandbox_permissions` for any reason, commands will be rejected.
</permissions instructions>

<apps_instructions>
## Apps (Connectors)
Apps (Connectors) can be explicitly triggered in user messages in the format `[$app-name](app://{connector_id})`. Apps can also be implicitly triggered as long as the context suggests usage of available apps.
An app is equivalent to a set of MCP tools within the `codex_apps` MCP.
An installed app's MCP tools are either provided to you already, or can be lazy-loaded through the `tool_search` tool. If `tool_search` is available, the apps that are searchable by `tools_search` will be listed by it.
Do not additionally call list_mcp_resources or list_mcp_resource_templates for apps.
</apps_instructions>

<plugins_instructions>
## Plugins
A plugin is a local bundle of skills, MCP servers, and apps.
### How to use plugins
- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list.
- MCP naming: Plugin-provided MCP tools keep standard MCP identifiers such as `mcp__server__tool`; use tool provenance to tell which plugin they come from.
- Trigger rules: If the user explicitly names a plugin, prefer capabilities associated with that plugin for that turn.
- Relationship to capabilities: Plugins are not invoked directly. Use their underlying skills, MCP tools, and app tools to help solve the task.
- Relevance: Determine what a plugin can help with from explicit user mention or from the plugin-associated skills, MCP tools, and apps exposed elsewhere in this turn.
- Missing/blocked: If the user requests a plugin that does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback.
</plugins_instructions>

<skills_instructions>
## Skills
A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and a short path that can be expanded into an absolute path using the skill roots table.
### Skill roots
- `r0` = `/home/user/.codex/skills/.system`
- `r1` = `/home/user/.codex/plugins/cache/openai-curated-remote/app-69312da8e4dc81919370cb86fd172b6c/7.0.0/skills`
- `r2` = `/home/user/.codex/plugins/cache/openai-curated-remote/github/0.1.8-2841cf9749ae/skills`
- `r3` = `/home/user/.codex/plugins/cache/openai-curated-remote/google-drive/0.1.11/skills`
### Available skills
- imagegen: Generate or edit raster images when the task benefits from AI-created bitmap visuals such as photos, illustrations, textures, sprites, mockups, or transparent-background cutouts. Use when Codex should create a brand-new image, transform an existing image, or derive visual variants from references, and the output should be a bitmap asset rather than repo-native code or vector. Do not use when the task is better handled by editing existing SVG/vector/code-native assets, extending an established icon or logo system, or building the visual directly in HTML/CSS/canvas. (file: r0/imagegen/SKILL.md)
- openai-docs: Use when the user asks how to build with OpenAI products or APIs, asks about Codex itself or choosing Codex surfaces, needs up-to-date official documentation with citations, help choosing the latest model for a use case, latest/current/default-model prompting guidance, or model upgrade and prompt-upgrade guidance; use OpenAI docs MCP tools for non-Codex docs questions, use the Codex manual helper first for broad Codex self-knowledge, and restrict fallback browsing to official OpenAI domains. (file: r0/openai-docs/SKILL.md)
- plugin-creator: Create and scaffold plugin directories for Codex with a required `.codex-plugin/plugin.json`, optional plugin folders/files, valid manifest defaults, and personal-marketplace entries by default. Use when Codex needs to create a new personal plugin, add optional plugin structure, generate or update marketplace entries for plugin ordering and availability metadata, or update an existing local plugin during development with the CLI-driven cachebuster and reinstall flow. (file: r0/plugin-creator/SKILL.md)
- skill-creator: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations. (file: r0/skill-creator/SKILL.md)
- skill-installer: Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos). (file: r0/skill-installer/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-batch-edit-photos: Apply consistent photo adjustments across a set of images so they look like they were edited together. Use this skill whenever the user says "make my photos look cohesive", "give all these the same style", "apply a warm and golden feel to all of these", "make this cinematic", "match the look across my photos", "edit all my travel photos the same way", "batch edit these", "make these consistent", "fix my phone photos", or uploads a folder of photos and wants a unified, polished result. Also triggers for requests like "apply a preset to all of these", "make these look professional", or "they were shot in mixed lighting — ca (file: r1/adobe-batch-edit-photos/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-create-mockups: Use when a user wants to see their logo, design, or sketch on a product or scene mockup — mugs, t-shirts, business cards, hats, phone screens, posters, billboards, or similar. Triggers on "create mockups", "show my logo on products", or any logo upload with a request to visualize it on items. Access: 🔐 Signed-In required | Gen AI: ✅ Adobe Firefly via `image_generate` used for design creation, sketch polishing, and mockup scene generation (file: r1/adobe-create-mockups/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-create-social-variations: Resize, crop, or export any image or video into platform-ready social media assets using Adobe Creative Cloud tools. Use this skill when a user wants to prepare a photo, image, or video for one or more social platforms — Instagram, TikTok, LinkedIn, Facebook, YouTube, Snapchat, Pinterest, Threads, or X/Twitter. Triggers on: "prepare my image for Instagram", "resize for TikTok", "get this ready to post", "make versions for all platforms", "social media sizes", "crop for stories", "export for LinkedIn", "resize my video for social", "make social media assets", or any request to adapt a photo or video for specific platforms. H (file: r1/adobe-create-social-variations/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-design-from-template: Create any visual design using Adobe Express templates — flyers, posters, social media posts (Instagram, Facebook, LinkedIn), business cards, invitations, greeting cards, resumes, cover letters, brochures, newsletters, certificates, presentations, YouTube thumbnails, email headers, logos, menus, and labels. Use this skill whenever the user wants to make, design, or build any visual — even if they just say "make me a flyer", "design a poster", "I need something for Instagram", "create an event invite", or "make a business card". Also handles browsing templates, editing text, replacing images, changing backgrounds, animatin (file: r1/adobe-design-from-template/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-edit-quick-cut: Create a punchy sizzle reel from a video using Adobe Quick Cut. Use this skill whenever a user wants to cut, trim, or shorten a video into highlights — including phrases like "make a sizzle reel", "make a highlight reel", "quick cut this", "cut the best parts", "shorten this video", "make a highlight clip", "summarize this video visually", or any request to produce a shorter edited version of a video. Use this skill for Quick Cut requests before suggesting manual editing in Premiere. Requires the user to upload a video file. (file: r1/adobe-edit-quick-cut/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-retouch-portraits: Bulk-retouch a folder of portrait photos using Adobe tools — designed for wedding photographers and event photographers who need fast, walk-away batch processing. Use this skill when the user says "retouch my photos", "batch process these portraits", "process my wedding photos", "clean up this folder of images", "run my headshots through Adobe", or uploads/selects a folder of photos and wants them polished and ready to review. Automatically applies auto-straighten, auto-tone, and auto-light to every image. Outputs a preview grid and download folder. Access: 🔐 Signed-In required | Gen AI: ❌ by default — optional background- (file: r1/adobe-retouch-portraits/SKILL.md)
- github:gh-address-comments: Address actionable GitHub pull request review feedback. Use when the user wants to inspect unresolved review threads, requested changes, or inline review comments on a PR, then implement selected fixes. Use the GitHub app for PR metadata and flat comment reads, and use the bundled GraphQL script via `gh` whenever thread-level state, resolution status, or inline review context matters. (file: r2/gh-address-comments/SKILL.md)
- github:gh-fix-ci: Use when a user asks to debug or fix failing GitHub PR checks that run in GitHub Actions. Use the GitHub app from this plugin for PR metadata and patch context, and use `gh` for Actions check and log inspection before implementing any approved fix. (file: r2/gh-fix-ci/SKILL.md)
- github:github: Triage and orient GitHub repository, pull request, and issue work through the connected GitHub app. Use when the user asks for general GitHub help, wants PR or issue summaries, or needs repository context before choosing a more specific GitHub workflow. (file: r2/github/SKILL.md)
- github:yeet: Publish local changes to GitHub by confirming scope, committing intentionally, pushing the branch, and opening a draft PR through the GitHub app from this plugin, with `gh` used only as a fallback where connector coverage is insufficient. (file: r2/yeet/SKILL.md)
- google-drive:google-docs: Prompt- and template-complete Google Docs creation and editing with explicit-instruction-authoritative structural preservation, including semantic roles, relationships, comparison dimensions, and instructed extensions; full-topology native-copy routing; source-grounded per-tab adaptation for past/example references; style-preserving hyperlink and table edits; canonical smart-chip-first authoring for dates and relevant supported people or Google resources; a file-backed advisory trusted read before existing-document writes; automatic protected-control awareness; direct connector APIs by default; DOCX-first import only when n (file: r3/google-docs/SKILL.md)
- google-drive:google-drive: Use connected Google Drive as the single entrypoint for Drive, Docs, Sheets, and Slides work. Use when the user wants to find, fetch, organize, share, export, copy, or delete Drive files, or summarize and edit Google Docs, Google Sheets, and Google Slides through one unified Google Drive plugin. (file: r3/google-drive/SKILL.md)
- google-drive:google-drive-comments: Write, reply to, and resolve Google Drive comments on Docs, Sheets, Slides, and Drive files with evidence-backed location context. Use when the user asks to leave comments, review a file with comments, respond to comment threads, or resolve Drive comments. (file: r3/google-drive-comments/SKILL.md)
- google-drive:google-sheets: Analyze and edit connected Google Sheets with range precision. Use when the user wants to create Google Sheets, find a spreadsheet, inspect tabs or ranges, search rows, plan formulas, create or repair charts, clean or restructure tables, write concise summaries, or make explicit cell-range updates. (file: r3/google-sheets/SKILL.md)
- google-drive:google-slides: Route Google Slides authoring requests and derive a design system from a native template or reference deck. Use this skill when the user provides an existing native Google Slides deck as a template, reference, or prior-period source, or asks to edit, update, repair, restyle, or clean up an existing native Google Slides deck. Use the Presentations skill instead for net-new presentation creation when no existing native Google Slides deck must be followed. (file: r3/google-slides/SKILL.md)
### How to use skills
- Discovery: The list above is the skills available in this session (name + description + short path). Skill bodies live on disk at the listed paths after expanding the matching alias from `### Skill roots`.
- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.
- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.
- How to use a skill (progressive disclosure):
  1) After deciding to use a skill, the main agent must expand the listed short `path` with the matching alias from `### Skill roots`, then open and read its `SKILL.md` completely before taking task actions. If a read is truncated or paginated, continue until EOF.
  2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the directory containing that expanded `SKILL.md` first, and only consider other paths if needed.
  3) If `SKILL.md` points to extra folders such as `references/`, use its routing instructions to identify the files required for the task. The main agent must read each required instruction or reference file itself before acting on it. Do not delegate reading, summarizing, or interpreting skill instructions to a subagent. Subagents may still perform task work when the selected skill allows it.
  4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.
  5) If `assets/` or templates exist, reuse them instead of recreating from scratch.
- Coordination and sequencing:
  - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.
  - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.
- Context hygiene:
  - Progressive disclosure applies to selecting relevant files, not partially reading a selected instruction file. Do not load unrelated references, scripts, or assets.
  - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.
  - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.
- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue.
</skills_instructions>

<recommended_plugins>
Here is a list of plugins that are available but not installed.

- Airtable (airtable@openai-curated-remote)
- Apollo.io (apollo@openai-curated-remote)
- Asana (asana@openai-curated-remote)
- Atlassian Rovo (atlassian-rovo@openai-curated-remote)
- Base44 (base44@openai-curated-remote)
- Box (box@openai-curated-remote)
- Cloudflare (cloudflare@openai-curated-remote)
- Codex Security (codex-security@openai-curated-remote)
- Figma (figma@openai-curated-remote)
- Gmail (gmail@openai-curated-remote)
- Google Calendar (google-calendar@openai-curated-remote)
- Granola (granola@openai-curated-remote)
- HeyGen (heygen@openai-curated-remote)
- HubSpot (hubspot@openai-curated-remote)
- HyperFrames by HeyGen (hyperframes@openai-curated-remote)
- Linear (linear@openai-curated-remote)
- Lovable (lovable@openai-curated-remote)
- Monday.com (monday-com@openai-curated-remote)
- Neon Postgres (neon-postgres@openai-curated-remote)
- Notion (notion@openai-curated-remote)
- OpenAI Developers (openai-developers@openai-curated-remote)
- Outlook Calendar (outlook-calendar@openai-curated-remote)
- Outlook Email (outlook-email@openai-curated-remote)
- PostHog (posthog@openai-curated-remote)
- Remotion (remotion@openai-curated-remote)
- Replit (replit@openai-curated-remote)
- Semrush (semrush@openai-curated-remote)
- Sentry (sentry@openai-curated-remote)
- SharePoint (sharepoint@openai-curated-remote)
- Slack (slack@openai-curated-remote)
- Stripe (stripe@openai-curated-remote)
- Supabase (supabase@openai-curated-remote)
- Superpowers (superpowers@openai-curated-remote)
- Teams (teams@openai-curated-remote)
- Vercel (vercel@openai-curated-remote)
- Wix (wix@openai-curated-remote)
- Zotero (zotero@openai-curated-remote)
</recommended_plugins>

# AGENTS.md instructions for /home/user/cdx-offload/sbdisp-c7c9d94b5596

<INSTRUCTIONS>
# Agent instructions — overdeck

audience: AI coding agents (codex included — this file is your entry point). Claude Code auto-loads it via the repo-root `CLAUDE.md` symlink; edit THIS file, never the symlink.

Working under `modules/harness/**` → also read `modules/harness/CLAUDE.md` (engine-bundle resolution, adapter/preset layout, canary fixture).

## Harness reliability — MANDATORY

ANY change to harness crash, restart, retry, checkpoint, supervision, or caller-completion behavior → read `docs/specs/2026-07-30-harness-reliability-lessons-and-plan.md` FIRST. It is canonical; NEVER restore v1-style daemon or automatic coordinator relaunch.

## UI work — MANDATORY

ANY change under `apps/web/src/**` or `packages/deck-ui/src/**` → read
`.claude/skills/od-ui-dev/SKILL.md` FIRST and obey it. Non-negotiable core:

- Compose existing `@overdeck/deck-ui` exports (`packages/deck-ui/src/index.ts` = the
  registry). NO hand-rolled tables/chips/menus/tooltips in apps/web.
- NEVER create a new primitive without explicit user approval — stop and report instead.
- Tokens only, both themes. Honest data — never fabricate values.
- Every deck-ui component registered in the `/design-system` gallery; barrel⊆gallery test
  and slopgate stay green — never suppress/baseline your own violations.

## Worktree isolation — MANDATORY

NEVER work in `/home/user/Projects/overdeck` itself (the shared main checkout) —
other agent sessions have uncommitted work there; `git restore`, `checkout --`/
`checkout .`, `stash push|pop|drop|clear`, `clean -f*`, `reset --hard` there
destroys it. Claim a worktree first: `~/.claude/bin/od-worktree add <slug>`,
then `cd .worktrees/<slug>` and work only there.

Enforced fail-closed, not by convention:
- Claude Code: PreToolUse hooks deny Edit/Write into the main checkout and the
  destructive git verbs above run against it.
- codex (`cdx exec`, incl. via `/ask-codex`), cursor-agent, and anything else
  launched under the agent shim chain: a `git` PATH shim blocks the same
  destructive verbs against the main checkout.

A refusal names the fix (`od-worktree add <slug>`) — run it, never retry raw.

## Verification

`pnpm --filter @overdeck/deck-ui test|typecheck`, `pnpm --filter web build|typecheck`,
collector: `bun test` in `collector/`. Playwright probes: SSE stream ⇒ `networkidle`
never fires — use `domcontentloaded` + `waitForSelector`.

## Landing

DEFAULT: work on a branch; land via `.claude/scripts/ship.sh` (guarded trunk),
driven by the orchestrator, not you. NEVER hand-type the merge/push cascade.

DIRECT LAND — owner-authorized escape hatch, ONLY when the land queue is the
bottleneck (queue depth stalls landing for hours) AND the orchestrator says so.
NEVER a default, NEVER a way to skip a red gate.

```bash
/usr/bin/git -C <worktree> -c core.hooksPath=<empty-dir> push origin HEAD:refs/heads/main
cd <repo-root> && bash packaging/deploy-local.sh   # MANDATORY — landing without deploying ships nothing
```

`/usr/bin/git` by absolute path: plain `git` is a PATH shim that reroutes `push`
into the land queue. Re-fetch and merge `origin/main` immediately before pushing —
main moves fast. A direct land skips the gate, so you own verification: run the
touched module's tests yourself and report what you did NOT verify.

</INSTRUCTIONS>

<environment_context>
  <cwd>/home/user/cdx-offload/sbdisp-c7c9d94b5596</cwd>
  <shell>bash</shell>
  <current_date>2026-08-08</current_date>
  <timezone>Asia/Jerusalem</timezone>
  <filesystem><workspace_roots><root>/home/user/cdx-offload/sbdisp-c7c9d94b5596</root></workspace_roots><permission_profile type="disabled"><file_system type="unrestricted" /></permission_profile></filesystem>
</environment_context>

[showing first 100 of 102 lines]
You are editing ONLY these files in this worktree:
- modules/systray/remote_dispatch.py
- modules/systray/command_router.py
- modules/systray/tests/test_remote_dispatch.py
- modules/systray/tests/test_command_router.py

Touch NOTHING else. No new files. No TODOs, no stubs, no placeholders, no skipped tests.
Comments: document only what is non-obvious about the CODE. NEVER write reasoning, rationale,
alternatives-considered, or changelog narration into the source. Default to zero comments.

GOAL (part 1 of 3): make agent dispatch FAIL CLOSED. Today `command_router._run_captured`
prints "RUNNING ON THE WORKSTATION" and runs the agent CLI uncontained when offload fails,
unless CDX_OFFLOAD_STRICT=1. That is a fork-bomb path. There must be NO environment variable
an agent can set that restores workstation execution.

Do exactly this:

1. In remote_dispatch.py add:

   def in_container() -> bool:
       """Machine-local evidence, not env: an env marker is agent-settable."""
       for probe in (Path("/run/.containerenv"), Path("/.dockerenv")):
           if probe.exists():
               return True
       try:
           cgroup = Path("/proc/self/cgroup").read_text(encoding="utf-8")
       except OSError:
           return False
       return "libpod" in cgroup or "docker" in cgroup

   Rewrite should_offload() to take no env at all:

   def should_offload() -> bool:
       return not in_container()

   Delete the CDX_NO_OFFLOAD branch and the OD_REMOTE_EXEC / HARNESS_SEAT_CONTAINER env
   branch entirely. Keep the module docstring accurate.

2. Give OffloadUnavailable a numeric exit code. Add module constants and use them at every
   existing raise site in remote_dispatch.py:

       EXIT_NO_NODE = 80      # registry unreadable / no reachable agent-seat host / no access door
       EXIT_CREDENTIAL = 81   # resolved credential file missing or unreadable
       EXIT_MIRROR = 82       # mkdir / rsync / git-mirror preparation failed
       EXIT_LAUNCH = 83       # launcher or container failed to start
       EXIT_UNCONTAINABLE = 84  # this invocation has no containerized path

   class OffloadUnavailable(RuntimeError):
       def __init__(self, message: str, code: int = EXIT_NO_NODE) -> None:
           super().__init__(message)
           self.code = code

   load_registry / candidate_hosts / access_for raise with EXIT_NO_NODE.
   open_session's mkdir and mirror-push failures raise with EXIT_MIRROR.

3. In command_router.py `_run_captured`, replace the whole fail-open block with an
   unconditional abort. No env is consulted. On OffloadUnavailable:

       print(f"{tool}: containment unavailable — {exc}", file=sys.stderr)
       return exc.code

   `should_offload()` now takes no argument. When should_offload() is False (we are already
   inside a container) the existing local `supervise(...)` path stands — that is the in-container
   execution, not a workstation fallback.

4. Close the execvpe hole. In command_router.main(), when `capture_log_path()` returns None the
   code currently calls os.execvpe and runs the agent CLI directly on the workstation. Change it
   so that path is taken ONLY when remote_dispatch.in_container() is True. Otherwise print to
   stderr a message naming the tool and the reason there is no containerized path for this
   invocation, and return remote_dispatch.EXIT_UNCONTAINABLE. Keep the message specific: say
   whether the reason is that the adapter captures no log for these arguments, or that no log
   directory was writable.

   Do NOT add any env var, flag, or config that re-enables the workstation path.

5. Tests. In tests/test_remote_dispatch.py add tests that:
   - should_offload() is True when in_container() is monkeypatched False, and False when True.
   - Setting CDX_NO_OFFLOAD=1, OD_REMOTE_EXEC=1, HARNESS_SEAT_CONTAINER=1, CDX_OFFLOAD_STRICT=0
     (all at once, via monkeypatch.setenv) does not change should_offload()'s answer.
   - OffloadUnavailable carries the right code from load_registry / candidate_hosts / access_for.

   In tests/test_command_router.py add tests that:
   - when open_session raises OffloadUnavailable(code=82), _run_captured/main returns 82,
     prints the cause on stderr, and NEVER calls supervise.
   - the same holds with every one of the four env vars above set to their "let me out" values.
   - a cdx invocation whose capture_log_path() is None returns EXIT_UNCONTAINABLE and never
     calls os.execvpe, when in_container() is False.

6. Fix a real test-isolation defect while you are here. These four tests currently escape their
   fakes and dispatch a REAL codex run to a real buildbox (94s suite):
     tests/test_command_router.py::test_codex_exec_captures_output_to_logfile_and_prints_only_path
     tests/test_cdx.py::test_main_execs_project_override_account
     tests/test_cdx.py::test_main_notifies_and_uses_fallback_for_broken_default
     tests/test_cdx.py::test_main_account_override_with_space_separated_value
   Cause: they fake the process launch but not remote_dispatch, so real host selection, real ssh
   and real rsync run. Fix it inside test_command_router.py only (leave test_cdx.py to part 3):
   monkeypatch remote_dispatch.in_container to return True in that test so no dispatch is
   attempted, or monkeypatch open_session with an explicit fake — whichever states the test's
   intent honestly. Never make a test pass by asserting the wrong behaviour.

[truncated]


# Agent instructions — overdeck

audience: AI coding agents (codex included — this file is your entry point). Claude Code auto-loads it via the repo-root `CLAUDE.md` symlink; edit THIS file, never the symlink.

Working under `modules/harness/**` → also read `modules/harness/CLAUDE.md` (engine-bundle resolution, adapter/preset layout, canary fixture).

## Harness reliability — MANDATORY

ANY change to harness crash, restart, retry, checkpoint, supervision, or caller-completion behavior → read `docs/specs/2026-07-30-harness-reliability-lessons-and-plan.md` FIRST. It is canonical; NEVER restore v1-style daemon or automatic coordinator relaunch.

## UI work — MANDATORY

ANY change under `apps/web/src/**` or `packages/deck-ui/src/**` → read
`.claude/skills/od-ui-dev/SKILL.md` FIRST and obey it. Non-negotiable core:

- Compose existing `@overdeck/deck-ui` exports (`packages/deck-ui/src/index.ts` = the
  registry). NO hand-rolled tables/chips/menus/tooltips in apps/web.
- NEVER create a new primitive without explicit user approval — stop and report instead.
- Tokens only, both themes. Honest data — never fabricate values.
- Every deck-ui component registered in the `/design-system` gallery; barrel⊆gallery test
  and slopgate stay green — never suppress/baseline your own violations.

## Worktree isolation — MANDATORY

NEVER work in `/home/user/Projects/overdeck` itself (the shared main checkout) —
other agent sessions have uncommitted work there; `git restore`, `checkout --`/
`checkout .`, `stash push|pop|drop|clear`, `clean -f*`, `reset --hard` there
destroys it. Claim a worktree first: `~/.claude/bin/od-worktree add <slug>`,
then `cd .worktrees/<slug>` and work only there.

Enforced fail-closed, not by convention:
- Claude Code: PreToolUse hooks deny Edit/Write into the main checkout and the
  destructive git verbs above run against it.
- codex (`cdx exec`, incl. via `/ask-codex`), cursor-agent, and anything else
  launched under the agent shim chain: a `git` PATH shim blocks the same
  destructive verbs against the main checkout.

A refusal names the fix (`od-worktree add <slug>`) — run it, never retry raw.

## Verification

`pnpm --filter @overdeck/deck-ui test|typecheck`, `pnpm --filter web build|typecheck`,
collector: `bun test` in `collector/`. Playwright probes: SSE stream ⇒ `networkidle`
never fires — use `domcontentloaded` + `waitForSelector`.

## Landing

DEFAULT: work on a branch; land via `.claude/scripts/ship.sh` (guarded trunk),
driven by the orchestrator, not you. NEVER hand-type the merge/push cascade.

DIRECT LAND — owner-authorized escape hatch, ONLY when the land queue is the
bottleneck (queue depth stalls landing for hours) AND the orchestrator says so.
NEVER a default, NEVER a way to skip a red gate.

```bash
/usr/bin/git -C <worktree> -c core.hooksPath=<empty-dir> push origin HEAD:refs/heads/main
cd <repo-root> && bash packaging/deploy-local.sh   # MANDATORY — landing without deploying ships nothing
```

`/usr/bin/git` by absolute path: plain `git` is a PATH shim that reroutes `push`
into the land queue. Re-fetch and merge `origin/main` immediately before pushing —
main moves fast. A direct land skips the gate, so you own verification: run the
touched module's tests yourself and report what you did NOT verify.

## Skills
A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and a short path that can be expanded into an absolute path using the skill roots table.
### Skill roots
- `r0` = `/home/user/.codex/skills/.system`
- `r1` = `/home/user/.codex/plugins/cache/openai-curated-remote/app-69312da8e4dc81919370cb86fd172b6c/7.0.0/skills`
- `r2` = `/home/user/.codex/plugins/cache/openai-curated-remote/github/0.1.8-2841cf9749ae/skills`
- `r3` = `/home/user/.codex/plugins/cache/openai-curated-remote/google-drive/0.1.11/skills`
### Available skills
- imagegen: Generate or edit raster images when the task benefits from AI-created bitmap visuals such as photos, illustrations, textures, sprites, mockups, or transparent-background cutouts. Use when Codex should create a brand-new image, transform an existing image, or derive visual variants from references, and the output should be a bitmap asset rather than repo-native code or vector. Do not use when the task is better handled by editing existing SVG/vector/code-native assets, extending an established icon or logo system, or building the visual directly in HTML/CSS/canvas. (file: r0/imagegen/SKILL.md)
- openai-docs: Use when the user asks how to build with OpenAI products or APIs, asks about Codex itself or choosing Codex surfaces, needs up-to-date official documentation with citations, help choosing the latest model for a use case, latest/current/default-model prompting guidance, or model upgrade and prompt-upgrade guidance; use OpenAI docs MCP tools for non-Codex docs questions, use the Codex manual helper first for broad Codex self-knowledge, and restrict fallback browsing to official OpenAI domains. (file: r0/openai-docs/SKILL.md)
- plugin-creator: Create and scaffold plugin directories for Codex with a required `.codex-plugin/plugin.json`, optional plugin folders/files, valid manifest defaults, and personal-marketplace entries by default. Use when Codex needs to create a new personal plugin, add optional plugin structure, generate or update marketplace entries for plugin ordering and availability metadata, or update an existing local plugin during development with the CLI-driven cachebuster and reinstall flow. (file: r0/plugin-creator/SKILL.md)
- skill-creator: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations. (file: r0/skill-creator/SKILL.md)
- skill-installer: Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos). (file: r0/skill-installer/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-batch-edit-photos: Apply consistent photo adjustments across a set of images so they look like they were edited together. Use this skill whenever the user says "make my photos look cohesive", "give all these the same style", "apply a warm and golden feel to all of these", "make this cinematic", "match the look across my photos", "edit all my travel photos the same way", "batch edit these", "make these consistent", "fix my phone photos", or uploads a folder of photos and wants a unified, polished result. Also triggers for requests like "apply a preset to all of these", "make these look professional", or "they were shot in mixed lighting — ca (file: r1/adobe-batch-edit-photos/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-create-mockups: Use when a user wants to see their logo, design, or sketch on a product or scene mockup — mugs, t-shirts, business cards, hats, phone screens, posters, billboards, or similar. Triggers on "create mockups", "show my logo on products", or any logo upload with a request to visualize it on items. Access: 🔐 Signed-In required | Gen AI: ✅ Adobe Firefly via `image_generate` used for design creation, sketch polishing, and mockup scene generation (file: r1/adobe-create-mockups/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-create-social-variations: Resize, crop, or export any image or video into platform-ready social media assets using Adobe Creative Cloud tools. Use this skill when a user wants to prepare a photo, image, or video for one or more social platforms — Instagram, TikTok, LinkedIn, Facebook, YouTube, Snapchat, Pinterest, Threads, or X/Twitter. Triggers on: "prepare my image for Instagram", "resize for TikTok", "get this ready to post", "make versions for all platforms", "social media sizes", "crop for stories", "export for LinkedIn", "resize my video for social", "make social media assets", or any request to adapt a photo or video for specific platforms. H (file: r1/adobe-create-social-variations/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-design-from-template: Create any visual design using Adobe Express templates — flyers, posters, social media posts (Instagram, Facebook, LinkedIn), business cards, invitations, greeting cards, resumes, cover letters, brochures, newsletters, certificates, presentations, YouTube thumbnails, email headers, logos, menus, and labels. Use this skill whenever the user wants to make, design, or build any visual — even if they just say "make me a flyer", "design a poster", "I need something for Instagram", "create an event invite", or "make a business card". Also handles browsing templates, editing text, replacing images, changing backgrounds, animatin (file: r1/adobe-design-from-template/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-edit-quick-cut: Create a punchy sizzle reel from a video using Adobe Quick Cut. Use this skill whenever a user wants to cut, trim, or shorten a video into highlights — including phrases like "make a sizzle reel", "make a highlight reel", "quick cut this", "cut the best parts", "shorten this video", "make a highlight clip", "summarize this video visually", or any request to produce a shorter edited version of a video. Use this skill for Quick Cut requests before suggesting manual editing in Premiere. Requires the user to upload a video file. (file: r1/adobe-edit-quick-cut/SKILL.md)
- app-69312da8e4dc81919370cb86fd172b6c:adobe-retouch-portraits: Bulk-retouch a folder of portrait photos using Adobe tools — designed for wedding photographers and event photographers who need fast, walk-away batch processing. Use this skill when the user says "retouch my photos", "batch process these portraits", "process my wedding photos", "clean up this folder of images", "run my headshots through Adobe", or uploads/selects a folder of photos and wants them polished and ready to review. Automatically applies auto-straighten, auto-tone, and auto-light to every image. Outputs a preview grid and download folder. Access: 🔐 Signed-In required | Gen AI: ❌ by default — optional background- (file: r1/adobe-retouch-portraits/SKILL.md)
- github:gh-address-comments: Address actionable GitHub pull request review feedback. Use when the user wants to inspect unresolved review threads, requested changes, or inline review comments on a PR, then implement selected fixes. Use the GitHub app for PR metadata and flat comment reads, and use the bundled GraphQL script via `gh` whenever thread-level state, resolution status, or inline review context matters. (file: r2/gh-address-comments/SKILL.md)
- github:gh-fix-ci: Use when a user asks to debug or fix failing GitHub PR checks that run in GitHub Actions. Use the GitHub app from this plugin for PR metadata and patch context, and use `gh` for Actions check and log inspection before implementing any approved fix. (file: r2/gh-fix-ci/SKILL.md)
- github:github: Triage and orient GitHub repository, pull request, and issue work through the connected GitHub app. Use when the user asks for general GitHub help, wants PR or issue summaries, or needs repository context before choosing a more specific GitHub workflow. (file: r2/github/SKILL.md)
- github:yeet: Publish local changes to GitHub by confirming scope, committing intentionally, pushing the branch, and opening a draft PR through the GitHub app from this plugin, with `gh` used only as a fallback where connector coverage is insufficient. (file: r2/yeet/SKILL.md)
- google-drive:google-docs: Prompt- and template-complete Google Docs creation and editing with explicit-instruction-authoritative structural preservation, including semantic roles, relationships, comparison dimensions, and instructed extensions; full-topology native-copy routing; source-grounded per-tab adaptation for past/example references; style-preserving hyperlink and table edits; canonical smart-chip-first authoring for dates and relevant supported people or Google resources; a file-backed advisory trusted read before existing-document writes; automatic protected-control awareness; direct connector APIs by default; DOCX-first import only when n (file: r3/google-docs/SKILL.md)
- google-drive:google-drive: Use connected Google Drive as the single entrypoint for Drive, Docs, Sheets, and Slides work. Use when the user wants to find, fetch, organize, share, export, copy, or delete Drive files, or summarize and edit Google Docs, Google Sheets, and Google Slides through one unified Google Drive plugin. (file: r3/google-drive/SKILL.md)
- google-drive:google-drive-comments: Write, reply to, and resolve Google Drive comments on Docs, Sheets, Slides, and Drive files with evidence-backed location context. Use when the user asks to leave comments, review a file with comments, respond to comment threads, or resolve Drive comments. (file: r3/google-drive-comments/SKILL.md)
- google-drive:google-sheets: Analyze and edit connected Google Sheets with range precision. Use when the user wants to create Google Sheets, find a spreadsheet, inspect tabs or ranges, search rows, plan formulas, create or repair charts, clean or restructure tables, write concise summaries, or make explicit cell-range updates. (file: r3/google-sheets/SKILL.md)
- google-drive:google-slides: Route Google Slides authoring requests and derive a design system from a native template or reference deck. Use this skill when the user provides an existing native Google Slides deck as a template, reference, or prior-period source, or asks to edit, update, repair, restyle, or clean up an existing native Google Slides deck. Use the Presentations skill instead for net-new presentation creation when no existing native Google Slides deck must be followed. (file: r3/google-slides/SKILL.md)
### How to use skills
- Discovery: The list above is the skills available in this session (name + description + short path). Skill bodies live on disk at the listed paths after expanding the matching alias from `### Skill roots`.
- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.
- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.
- How to use a skill (progressive disclosure):
  1) After deciding to use a skill, the main agent must expand the listed short `path` with the matching alias from `### Skill roots`, then open and read its `SKILL.md` completely before taking task actions. If a read is truncated or paginated, continue until EOF.
  2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the directory containing that expanded `SKILL.md` first, and only consider other paths if needed.
  3) If `SKILL.md` points to extra folders such as `references/`, use its routing instructions to identify the files required for the task. The main agent must read each required instruction or reference file itself before acting on it. Do not delegate reading, summarizing, or interpreting skill instructions to a subagent. Subagents may still perform task work when the selected skill allows it.
  4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.
  5) If `assets/` or templates exist, reuse them instead of recreating from scratch.
- Coordination and sequencing:
  - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.
  - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.
- Context hygiene:
  - Progressive disclosure applies to selecting relevant files, not partially reading a selected instruction file. Do not load unrelated references, scripts, or assets.
  - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.
  - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.
- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue.


Summary: auto


Implemented in the four allowed files only:

- `modules/systray/remote_dispatch.py`: fail-closed offload detection + exit code contract
  - Added `in_container()` using filesystem/cgroup probes only.
  - Changed `should_offload()` to `return not in_container()` with no env handling.
  - Removed env-based opt-out/re-entry branches (`CDX_NO_OFFLOAD`, `OD_REMOTE_EXEC`, `HARNESS_SEAT_CONTAINER`, `CDX_OFFLOAD_STRICT`) from the dispatch logic.
  - Added module constants:
    - `EXIT_NO_NODE = 80`
    - `EXIT_CREDENTIAL = 81`
    - `EXIT_MIRROR = 82`
    - `EXIT_LAUNCH = 83`
    - `EXIT_UNCONTAINABLE = 84`
  - Updated `OffloadUnavailable` to carry `code` and default to `EXIT_NO_NODE`.
  - Wired existing raise sites to use codes, including:
    - `load_registry`, `candidate_hosts`, `access_for`, `select_host` no-host path -> `EXIT_NO_NODE`
    - `open_session` mkdir/rsync/mirror prep failures -> `EXIT_MIRROR`

- `modules/systray/command_router.py`: closed workstation fallback and exec-vpe hole
  - `_run_captured` now fails closed on `OffloadUnavailable`:
    - prints `"{tool}: containment unavailable — {exc}"`
    - returns `exc.code`
  - Updated `_run_captured` to use `should_offload()` with no args.
  - In `main`, `capture_log_path() is None` branch now:
    - only executes direct `os.execvpe` when `remote_dispatch.in_container()` is `True`
    - otherwise returns `remote_dispatch.EXIT_UNCONTAINABLE` with explicit stderr reason:
      - no writable log directory
      - or adapter captures no log for these arguments

- `modules/systray/tests/test_remote_dispatch.py`
  - Added offload-container tests:
    - `should_offload()` true/false based on monkeypatched `in_container`
    - env escape variables together do not affect result
  - Added code assertions for `OffloadUnavailable.code`:
    - `load_registry`, `candidate_hosts`, `access_for` use `EXIT_NO_NODE`
    - `open_session` mirror prep failure uses `EXIT_MIRROR`

- `modules/systray/tests/test_command_router.py`
  - Fixed test isolation in `test_codex_exec_captures_output_to_logfile_and_prints_only_path` by monkeypatching `remote_dispatch.in_container` to `True` so real dispatch isn’t reached.
  - Updated `_run_captured` patching to new no-arg `should_offload` signature.
  - Added fail-closed tests for `OffloadUnavailable(code=82)`:
    - both `_run_captured` and `main` return `82`
    - stderr includes containment message
    - `supervise` is not called
    - same behavior under “let-me-out” env vars
  - Added `capture_log_path is None` test to ensure `EXIT_UNCONTAINABLE`, no `os.execvpe`, and specific reasoned message when not in container.

No other files were touched. No tests were run. If you want, I can run just the updated systray tests next.