{"owner":"metalbear-co","repo":"mirrord","hasSkills":true,"totalSkillsCount":8,"totalTokensCount":4820,"categories":["anthropic-skill","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["packages/wizard/tsconfig.json","packages/wizard/package.json","packages/ui/package.json","AGENTS.md","packages/monitor/tsconfig.json","packages/ui/tsconfig.json","packages/monitor/package.json","packages/wizard/BUSINESS_LOGIC.md"],"skills":{"packages/wizard/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.tsx\", \"src/**/*.test.ts\"]\n}\n","packages/wizard/package.json":"{\n  \"name\": \"mirrord-wizard\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Config wizard feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"typecheck\": \"tsc\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"prepare\": \"cd ../.. && husky packages/wizard/.husky\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.469.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"eslint --fix\",\n      \"prettier --write\"\n    ],\n    \"*.{js,jsx,json,css,md}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.1.0\",\n    \"@types/node\": \"^22.5.5\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"husky\": \"^9.1.7\",\n    \"jsdom\": \"^25.0.1\",\n    \"lint-staged\": \"^16.2.7\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.17\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","packages/ui/package.json":"{\n  \"name\": \"mirrord-ui\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\"\n  },\n  \"dependencies\": {\n    \"@fontsource/poppins\": \"^5.2.7\",\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.577.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"autoprefixer\": \"^10.4.20\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"postcss\": \"^8.4.49\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n","AGENTS.md":"# mirrord\n\n## Overview\n\nmirrord is a tool that lets developers run local processes in the context of their Kubernetes cloud environment.\n\n### Core Crates\n\n- `mirrord-layer`: gets loaded into the user's process via `LD_PRELOAD`/`DYLD_INSERT_LIBRARIES`. Intercepts libc\ncalls (files, networking, DNS, env, ...) and turns them into protocol messages sent to the intproxy.\n- `mirrord-intproxy`: a local process spawned by the CLI that bridges N layers and 1 agent. Matches requests to\nresponses, handles reconnects, and routes messages to the right feature proxy.\n- `mirrord-agent`: the in-cluster component of mirrord. Runs in the target pods' context and network namespace. Does the\nactual I/O work requested by the layers.\n- `mirrord-protocol`: defines the shared messages (`ClientMessage`, `DaemonMessage`) sent between layer/intproxy/agent.\n- `mirrord-config`: config types and validation. Used by the CLI and layer to decide what features are enabled and what\ntarget to use. Every option records the plan it needs (`oss`, `team` or `enterprise`, per its docs page) as\n`x-mirrord-plan` in the schema, as a `mirrord_config::plan::Plan`: `#[config(plan = Team)]` on `MirrordConfig`\nfields, `#[schemars(extend(\"x-mirrord-plan\" = crate::plan::Plan::Team))]` elsewhere. Nested options inherit it, except that every option under\n`feature` and every target kind needs its own; tests in `mirrord-mcp` fail on an option without one.\n- `mirrord`: the CLI that resolves configuration, creates or connects to the agent, starts the intproxy, and launches\nthe user's local process with the mirrord layer loaded.\n- `mirrord-mcp`: the MCP server behind `mirrord mcp`, which exposes mirrord to AI agents over stdio. Tools are\nregistered in its `tools` module and must be answered offline, from what is compiled into the binary. Usage is\nreported through `mirrord-analytics`, and every new tool needs a variant in its `McpTool` telemetry enum. The docs and\nskills it answers from are vendored into `mirrord/mcp/corpus` from pinned upstream commits: never edit them by hand,\nbump them with `cargo xtask corpus sync --bump` (the release PR does).\n\n## Command Reference\n\n### Compiling\n\n```bash\n# check the entire workspace at once\n# always use when a change spans multiple crates instead of checking each crate individually\nCARGO_BUILD_WARNINGS=deny cargo clippy --all-targets --all-features --keep-going\n\n# check a specific crate\n# the agent is linux only\nCARGO_BUILD_WARNINGS=deny cargo clippy -p mirrord-agent --target x86_64-unknown-linux-gnu --keep-going\n\n# layer and cli bundled with the new layer\n# use only when a fresh mirrord + layer binary is needed for testing\ncargo xtask build-cli\n```\n\nUse `--keep-going` to surface all errors at once. Use `clippy` instead of `check` to lint + compile simultaneously.\n\n### Testing\n\n```bash\n# integration tests\n# requires building the cli first with `xtask build-cli`\ncargo xtask test-integration\n\n# filtered integration tests\ncargo xtask test-integration -- outgoing_udp --nocapture\n\n# unit tests\ncargo xtask test-ut\n\n# filtered unit tests\ncargo xtask test-ut -- resolve_url_happy_path -- --nocapture\n```\n\nNever write unit tests unless explicitly asked. Run the existing tests to verify a change.\n\n### Styling\n\n```bash\n# Formatting\ncargo fmt\n```\n\n## Simplicity and Reuse\n\nmirrord is actively maintained by dozens of people, it is not a greenfield project. When adding or changing things,\nmaximize simplicity. Reuse existing abstractions and codepaths instead of introducing new ones. Every new path is\nsomething someone has to understand, maintain, and keep compatible.\n\nAvoid extracting trivial, self-contained logic into a function used only once. Keep it near its point of use when the\nhelper would merely add indirection or exist to make a tiny test possible. Extract a function when it is reused or hides\nnon-obvious details that would distract from the surrounding flow. Test meaningful behavior rather than trivial\nwrappers around a library API.\n\n## Comments and Documentation\n\nDon't write comments explaining what code does, the code should speak for itself. Instead, focus on _why_ something\nexists: doc comments that explain the problem a function or struct solves and how it fits into the bigger picture are\nfar more valuable than ones that restate the type signature. Module-level doc comments that give a high-level overview\nof what a file is responsible for are also very helpful, as they give readers the context to understand the code below.\nmirrord has a lot of moving pieces and stability is critical, so document tricky or non-obvious behavior clearly.\n\nWrite comments for readers of the resulting code, not reviewers of the patch. Comments must stand alone after merge and\ndescribe the current behavior, intent, invariant, or non-obvious tradeoff. Don't narrate the edit or use patch-relative\nlanguage such as `the existing implementation`, `the new approach`, `now`, `previously`, `this change`, or\n`we added/removed`. Include historical context only when it is necessary to explain why the current code deliberately\ndiffers from an otherwise-obvious alternative.\n\n## Stack Usage\n\nThe CLI polls its whole runtime on the main thread, and on Windows that thread only gets the `/STACK` linked in\n`mirrord/cli/build.rs`. Debug builds are hit hardest: a function's frame keeps a slot for every future it builds\nbefore awaiting it, so one `match` with a large future per arm pays for all of them.\n\n- Put `#[mirrord_macros::boxed_future]` (above `#[tracing::instrument]`) on an `async fn` with a large future, such as\n  a subcommand or a connection step: it builds its future on the heap, and callers keep writing `f(..).await`.\n  `Box::pin(f(..))` and `.boxed()` don't help in a debug build, since `f(..)` is still built in the caller's frame first.\n- On a stack overflow, the Windows CLI prints every frame with its size, largest first. Windows CI runs\n  `scripts/win_stack_check.ps1`, which fails when the CLI outgrows its budget and shows that report.\n- `scripts/win_stack_report.ps1` measures peak stack and large frames locally.\n\n## Style Guideline\n\n- Keep imports at file top (no function-local `use`).\n- Prefer `to_owned` for `&str` → `String`.\n- Always use `foo.rs` instead of `foo/mod.rs` for module roots.\n- Run styling commands after every edit.\n","packages/monitor/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.ts\", \"src/**/*.test.tsx\"]\n}\n","packages/ui/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"paths\": {\n      \"@mirrord/monitor/theme\": [\"../monitor/src/theme.ts\"],\n      \"@mirrord/monitor/events\": [\"../monitor/src/events.tsx\"],\n      \"@mirrord/monitor\": [\"../monitor/src/index.tsx\"],\n      \"@mirrord/wizard\": [\"../wizard/src/index.tsx\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n","packages/monitor/package.json":"{\n  \"name\": \"session-monitor-frontend\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Session monitor feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"typecheck\": \"tsc -b\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"lucide-react\": \"^0.577.0\",\n    \"posthog-js\": \"^1.364.6\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","packages/wizard/BUSINESS_LOGIC.md":"# mirrord Wizard Frontend - Business Logic\n\n## Overview\n\nThe wizard frontend is a React application that helps users create `mirrord.json` configuration files through a guided wizard interface. It connects to a backend API to fetch Kubernetes cluster information.\n\n## Application Flow\n\n### 1. Entry Point (App.tsx → Homepage.tsx)\n\n1. App checks if user is \"returning\" via API call to `/api/v1/is-returning`\n2. Based on response, shows either:\n   - **New User**: `HomepageNewUser` - Welcome message + two panels (Learn First / Skip to Config)\n   - **Returning User**: `HomepageReturning` - Welcome back + two panels (Create Config / Learn)\n\n### 2. Homepage Panels\n\nEach homepage has two clickable panels that open different wizard flows:\n\n**New User:**\n\n- \"Learn About mirrord First\" → IntroStep + 6 Learning Steps + BoilerplateStep + ConfigStep\n- \"Skip to Configuration\" → BoilerplateStep + ConfigStep\n\n**Returning User:**\n\n- \"Create Configuration\" → BoilerplateStep + ConfigStep\n- \"Learn About mirrord\" → 6 Learning Steps + BoilerplateStep + ConfigStep\n\n### 3. Wizard Steps\n\n#### Step: BoilerplateStep\n\nUser selects one of three modes:\n\n- **Filtering Mode** (steal): Selective traffic stealing with HTTP header/path filters\n- **Mirror Mode**: Copy traffic without disrupting remote service\n- **Replace Mode**: Completely substitute remote service (copy_target + scale_down)\n\n#### Step: ConfigStep (ConfigTabs)\n\nThree tabs:\n\n1. **Target Tab**: Select namespace, target type, and specific target from K8s cluster\n2. **Network Tab**: Configure incoming traffic, filters, and port mappings\n3. **Export Tab**: View JSON, copy to clipboard, or download file\n\n## API Routes\n\n```typescript\nconst ALL_API_ROUTES = {\n  isReturning: \"/api/v1/is-returning\",\n  clusterDetails: \"/api/v1/cluster-details\", // Returns { namespaces: string[], target_types: string[] }\n  targets: (namespace: string, targetType?: string) =>\n    \"/api/v1/namespace/{namespace}/targets?target_type={targetType}\",\n  // Returns Target[] where Target = { target_path, target_namespace, detected_ports }\n};\n```\n\n## Config Data Structure\n\n### Default Config\n\n```typescript\nconst DefaultConfig: LayerFileConfig = {\n  feature: {\n    network: {\n      incoming: { mode: \"mirror\" },\n      outgoing: true,\n    },\n    fs: \"read\",\n    env: true,\n  },\n};\n```\n\n### Key Config Sections\n\n1. **target**: `{ path: \"deployment/name\", namespace: \"default\" }`\n2. **feature.network.incoming.mode**: `\"mirror\"` | `\"steal\"`\n3. **feature.network.incoming.ports**: `number[]` - ports to intercept\n4. **feature.network.incoming.port_mapping**: `[localPort, remotePort][]`\n5. **feature.network.incoming.http_filter**: Header/path filters for selective stealing\n6. **feature.copy_target**: `{ enabled: boolean, scale_down: boolean }` - for Replace mode\n\n## Config Manipulation Functions (JsonUtils.tsx)\n\n### Mode/Boilerplate\n\n- `readBoilerplateType(config)` → `\"steal\"` | `\"mirror\"` | `\"replace\"` | `\"custom\"`\n- `updateConfigMode(mode, config)` → Sets `incoming.mode`\n- `updateConfigCopyTarget(enabled, scaleDown, config)` → Sets `copy_target`\n\n### Target\n\n- `readCurrentTargetDetails(config)` → `{ type: string, name?: string }`\n- `updateConfigTarget(config, targetPath, namespace)` → Sets `target`\n\n### Incoming Network\n\n- `readIncoming(config)` → Returns entire `network.incoming` section\n- `updateIncoming(config, newIncoming)` → Replaces `network.incoming`\n\n### HTTP Filters\n\n- `readCurrentFilters(config)` → `{ filters: UiHttpFilter[], operator: \"any\"|\"all\"|null }`\n- `updateConfigFilter(filters, operator, config)` → Sets `http_filter`\n- `removeSingleFilter(filter, config)` → Removes one filter\n- `disableConfigFilter(config)` → Clears all filters\n- `regexificationRay(value)` → Converts exact match to regex: `\"foo\"` → `\"^foo$\"`\n\nFilter types:\n\n```typescript\ninterface UiHttpFilter {\n  value: string; // The filter pattern (regex)\n  type: \"header\" | \"path\";\n}\n```\n\n### Ports\n\n- `readCurrentPorts(config)` → `number[]` - ports from `incoming.ports`\n- `updateConfigPorts(ports, config)` → Sets `incoming.ports` (and `http_filter.ports` if filters exist)\n- `readCurrentPortMapping(config)` → `[localPort, remotePort][]`\n- `updateConfigPortMapping(mappings, config)` → Sets `incoming.port_mapping`\n- `addRemoveOrUpdateMapping(remote, local, config)` → Smart mapping update\n- `getLocalPort(remotePort, config)` → Returns mapped local port or remote if no mapping\n- `removePortandMapping(remotePort, config)` → Removes port and its mapping\n- `disablePortsAndMapping(config)` → Clears both ports and mappings\n\n### JSON Export\n\n- `getConfigString(config)` → Pretty-printed JSON (removes `incoming.ports` in replace mode)\n\n## State Management\n\n### UserDataContext\n\n- `UserDataContext`: Stores boolean for `isReturning` status\n- `ConfigDataContext`: Stores current `LayerFileConfig` and setter\n- `ConfigDataContextProvider`: Wraps app with config state (initialized to `DefaultConfig`)\n\n## UI Components Needed\n\n### Core\n\n- **Wizard**: Dialog with header (title, step counter, mode badge), content area, footer (Back/Next)\n- **Panel**: Card with title, description, button → opens wizard\n\n### Form Components (from @metalbear/ui)\n\n- Button, Input, Textarea, Label\n- Select (SelectTrigger, SelectContent, SelectItem, SelectValue)\n- Tabs (TabsList, TabsTrigger, TabsContent)\n- RadioGroup (RadioGroupItem)\n- Switch, Checkbox, Separator, Badge\n- Dialog (DialogContent, DialogTitle, DialogDescription)\n- Toast (ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose)\n- Tooltip (TooltipProvider, Tooltip, TooltipTrigger, TooltipContent)\n\n### Custom (keep local)\n\n- **Card**: Simple card with CardHeader, CardTitle, CardDescription, CardContent, CardFooter\n- **Popover**: For target search dropdown (not in @metalbear/ui)\n\n## Assets\n\n- `mirrord-logo.svg` - Logo for homepage\n- `mirrord-architecture.svg` - Architecture diagram for learning steps\n- `flow-diagram.png` - Feedback loop diagram for learning steps\n\n## Key Business Rules\n\n1. **Replace Mode**: Sets `copy_target.enabled=true`, `copy_target.scale_down=true`, mode=\"steal\"\n2. **Mirror Mode**: Sets `copy_target.enabled=false`, mode=\"mirror\"\n3. **Filtering Mode**: Sets `copy_target.enabled=false`, mode=\"steal\" (allows filters)\n4. **Port Conflicts**: Local ports must be unique across all mappings\n5. **Filter Ports**: When filters exist, ports are synced to `http_filter.ports`\n6. **Target Required**: Cannot proceed to Network tab without selecting a target\n7. **Replace Mode Restrictions**: Cannot delete auto-detected ports, no `incoming.ports` in export\n"},"files":{"packages/wizard/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.tsx\", \"src/**/*.test.ts\"]\n}\n","packages/wizard/package.json":"{\n  \"name\": \"mirrord-wizard\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Config wizard feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"typecheck\": \"tsc\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"prepare\": \"cd ../.. && husky packages/wizard/.husky\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.469.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"eslint --fix\",\n      \"prettier --write\"\n    ],\n    \"*.{js,jsx,json,css,md}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.1.0\",\n    \"@types/node\": \"^22.5.5\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"husky\": \"^9.1.7\",\n    \"jsdom\": \"^25.0.1\",\n    \"lint-staged\": \"^16.2.7\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.17\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","packages/ui/package.json":"{\n  \"name\": \"mirrord-ui\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\"\n  },\n  \"dependencies\": {\n    \"@fontsource/poppins\": \"^5.2.7\",\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.577.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"autoprefixer\": \"^10.4.20\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"postcss\": \"^8.4.49\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n","AGENTS.md":"# mirrord\n\n## Overview\n\nmirrord is a tool that lets developers run local processes in the context of their Kubernetes cloud environment.\n\n### Core Crates\n\n- `mirrord-layer`: gets loaded into the user's process via `LD_PRELOAD`/`DYLD_INSERT_LIBRARIES`. Intercepts libc\ncalls (files, networking, DNS, env, ...) and turns them into protocol messages sent to the intproxy.\n- `mirrord-intproxy`: a local process spawned by the CLI that bridges N layers and 1 agent. Matches requests to\nresponses, handles reconnects, and routes messages to the right feature proxy.\n- `mirrord-agent`: the in-cluster component of mirrord. Runs in the target pods' context and network namespace. Does the\nactual I/O work requested by the layers.\n- `mirrord-protocol`: defines the shared messages (`ClientMessage`, `DaemonMessage`) sent between layer/intproxy/agent.\n- `mirrord-config`: config types and validation. Used by the CLI and layer to decide what features are enabled and what\ntarget to use. Every option records the plan it needs (`oss`, `team` or `enterprise`, per its docs page) as\n`x-mirrord-plan` in the schema, as a `mirrord_config::plan::Plan`: `#[config(plan = Team)]` on `MirrordConfig`\nfields, `#[schemars(extend(\"x-mirrord-plan\" = crate::plan::Plan::Team))]` elsewhere. Nested options inherit it, except that every option under\n`feature` and every target kind needs its own; tests in `mirrord-mcp` fail on an option without one.\n- `mirrord`: the CLI that resolves configuration, creates or connects to the agent, starts the intproxy, and launches\nthe user's local process with the mirrord layer loaded.\n- `mirrord-mcp`: the MCP server behind `mirrord mcp`, which exposes mirrord to AI agents over stdio. Tools are\nregistered in its `tools` module and must be answered offline, from what is compiled into the binary. Usage is\nreported through `mirrord-analytics`, and every new tool needs a variant in its `McpTool` telemetry enum. The docs and\nskills it answers from are vendored into `mirrord/mcp/corpus` from pinned upstream commits: never edit them by hand,\nbump them with `cargo xtask corpus sync --bump` (the release PR does).\n\n## Command Reference\n\n### Compiling\n\n```bash\n# check the entire workspace at once\n# always use when a change spans multiple crates instead of checking each crate individually\nCARGO_BUILD_WARNINGS=deny cargo clippy --all-targets --all-features --keep-going\n\n# check a specific crate\n# the agent is linux only\nCARGO_BUILD_WARNINGS=deny cargo clippy -p mirrord-agent --target x86_64-unknown-linux-gnu --keep-going\n\n# layer and cli bundled with the new layer\n# use only when a fresh mirrord + layer binary is needed for testing\ncargo xtask build-cli\n```\n\nUse `--keep-going` to surface all errors at once. Use `clippy` instead of `check` to lint + compile simultaneously.\n\n### Testing\n\n```bash\n# integration tests\n# requires building the cli first with `xtask build-cli`\ncargo xtask test-integration\n\n# filtered integration tests\ncargo xtask test-integration -- outgoing_udp --nocapture\n\n# unit tests\ncargo xtask test-ut\n\n# filtered unit tests\ncargo xtask test-ut -- resolve_url_happy_path -- --nocapture\n```\n\nNever write unit tests unless explicitly asked. Run the existing tests to verify a change.\n\n### Styling\n\n```bash\n# Formatting\ncargo fmt\n```\n\n## Simplicity and Reuse\n\nmirrord is actively maintained by dozens of people, it is not a greenfield project. When adding or changing things,\nmaximize simplicity. Reuse existing abstractions and codepaths instead of introducing new ones. Every new path is\nsomething someone has to understand, maintain, and keep compatible.\n\nAvoid extracting trivial, self-contained logic into a function used only once. Keep it near its point of use when the\nhelper would merely add indirection or exist to make a tiny test possible. Extract a function when it is reused or hides\nnon-obvious details that would distract from the surrounding flow. Test meaningful behavior rather than trivial\nwrappers around a library API.\n\n## Comments and Documentation\n\nDon't write comments explaining what code does, the code should speak for itself. Instead, focus on _why_ something\nexists: doc comments that explain the problem a function or struct solves and how it fits into the bigger picture are\nfar more valuable than ones that restate the type signature. Module-level doc comments that give a high-level overview\nof what a file is responsible for are also very helpful, as they give readers the context to understand the code below.\nmirrord has a lot of moving pieces and stability is critical, so document tricky or non-obvious behavior clearly.\n\nWrite comments for readers of the resulting code, not reviewers of the patch. Comments must stand alone after merge and\ndescribe the current behavior, intent, invariant, or non-obvious tradeoff. Don't narrate the edit or use patch-relative\nlanguage such as `the existing implementation`, `the new approach`, `now`, `previously`, `this change`, or\n`we added/removed`. Include historical context only when it is necessary to explain why the current code deliberately\ndiffers from an otherwise-obvious alternative.\n\n## Stack Usage\n\nThe CLI polls its whole runtime on the main thread, and on Windows that thread only gets the `/STACK` linked in\n`mirrord/cli/build.rs`. Debug builds are hit hardest: a function's frame keeps a slot for every future it builds\nbefore awaiting it, so one `match` with a large future per arm pays for all of them.\n\n- Put `#[mirrord_macros::boxed_future]` (above `#[tracing::instrument]`) on an `async fn` with a large future, such as\n  a subcommand or a connection step: it builds its future on the heap, and callers keep writing `f(..).await`.\n  `Box::pin(f(..))` and `.boxed()` don't help in a debug build, since `f(..)` is still built in the caller's frame first.\n- On a stack overflow, the Windows CLI prints every frame with its size, largest first. Windows CI runs\n  `scripts/win_stack_check.ps1`, which fails when the CLI outgrows its budget and shows that report.\n- `scripts/win_stack_report.ps1` measures peak stack and large frames locally.\n\n## Style Guideline\n\n- Keep imports at file top (no function-local `use`).\n- Prefer `to_owned` for `&str` → `String`.\n- Always use `foo.rs` instead of `foo/mod.rs` for module roots.\n- Run styling commands after every edit.\n","packages/monitor/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.ts\", \"src/**/*.test.tsx\"]\n}\n","packages/ui/tsconfig.json":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"paths\": {\n      \"@mirrord/monitor/theme\": [\"../monitor/src/theme.ts\"],\n      \"@mirrord/monitor/events\": [\"../monitor/src/events.tsx\"],\n      \"@mirrord/monitor\": [\"../monitor/src/index.tsx\"],\n      \"@mirrord/wizard\": [\"../wizard/src/index.tsx\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n","packages/monitor/package.json":"{\n  \"name\": \"session-monitor-frontend\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Session monitor feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"typecheck\": \"tsc -b\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"lucide-react\": \"^0.577.0\",\n    \"posthog-js\": \"^1.364.6\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","packages/wizard/BUSINESS_LOGIC.md":"# mirrord Wizard Frontend - Business Logic\n\n## Overview\n\nThe wizard frontend is a React application that helps users create `mirrord.json` configuration files through a guided wizard interface. It connects to a backend API to fetch Kubernetes cluster information.\n\n## Application Flow\n\n### 1. Entry Point (App.tsx → Homepage.tsx)\n\n1. App checks if user is \"returning\" via API call to `/api/v1/is-returning`\n2. Based on response, shows either:\n   - **New User**: `HomepageNewUser` - Welcome message + two panels (Learn First / Skip to Config)\n   - **Returning User**: `HomepageReturning` - Welcome back + two panels (Create Config / Learn)\n\n### 2. Homepage Panels\n\nEach homepage has two clickable panels that open different wizard flows:\n\n**New User:**\n\n- \"Learn About mirrord First\" → IntroStep + 6 Learning Steps + BoilerplateStep + ConfigStep\n- \"Skip to Configuration\" → BoilerplateStep + ConfigStep\n\n**Returning User:**\n\n- \"Create Configuration\" → BoilerplateStep + ConfigStep\n- \"Learn About mirrord\" → 6 Learning Steps + BoilerplateStep + ConfigStep\n\n### 3. Wizard Steps\n\n#### Step: BoilerplateStep\n\nUser selects one of three modes:\n\n- **Filtering Mode** (steal): Selective traffic stealing with HTTP header/path filters\n- **Mirror Mode**: Copy traffic without disrupting remote service\n- **Replace Mode**: Completely substitute remote service (copy_target + scale_down)\n\n#### Step: ConfigStep (ConfigTabs)\n\nThree tabs:\n\n1. **Target Tab**: Select namespace, target type, and specific target from K8s cluster\n2. **Network Tab**: Configure incoming traffic, filters, and port mappings\n3. **Export Tab**: View JSON, copy to clipboard, or download file\n\n## API Routes\n\n```typescript\nconst ALL_API_ROUTES = {\n  isReturning: \"/api/v1/is-returning\",\n  clusterDetails: \"/api/v1/cluster-details\", // Returns { namespaces: string[], target_types: string[] }\n  targets: (namespace: string, targetType?: string) =>\n    \"/api/v1/namespace/{namespace}/targets?target_type={targetType}\",\n  // Returns Target[] where Target = { target_path, target_namespace, detected_ports }\n};\n```\n\n## Config Data Structure\n\n### Default Config\n\n```typescript\nconst DefaultConfig: LayerFileConfig = {\n  feature: {\n    network: {\n      incoming: { mode: \"mirror\" },\n      outgoing: true,\n    },\n    fs: \"read\",\n    env: true,\n  },\n};\n```\n\n### Key Config Sections\n\n1. **target**: `{ path: \"deployment/name\", namespace: \"default\" }`\n2. **feature.network.incoming.mode**: `\"mirror\"` | `\"steal\"`\n3. **feature.network.incoming.ports**: `number[]` - ports to intercept\n4. **feature.network.incoming.port_mapping**: `[localPort, remotePort][]`\n5. **feature.network.incoming.http_filter**: Header/path filters for selective stealing\n6. **feature.copy_target**: `{ enabled: boolean, scale_down: boolean }` - for Replace mode\n\n## Config Manipulation Functions (JsonUtils.tsx)\n\n### Mode/Boilerplate\n\n- `readBoilerplateType(config)` → `\"steal\"` | `\"mirror\"` | `\"replace\"` | `\"custom\"`\n- `updateConfigMode(mode, config)` → Sets `incoming.mode`\n- `updateConfigCopyTarget(enabled, scaleDown, config)` → Sets `copy_target`\n\n### Target\n\n- `readCurrentTargetDetails(config)` → `{ type: string, name?: string }`\n- `updateConfigTarget(config, targetPath, namespace)` → Sets `target`\n\n### Incoming Network\n\n- `readIncoming(config)` → Returns entire `network.incoming` section\n- `updateIncoming(config, newIncoming)` → Replaces `network.incoming`\n\n### HTTP Filters\n\n- `readCurrentFilters(config)` → `{ filters: UiHttpFilter[], operator: \"any\"|\"all\"|null }`\n- `updateConfigFilter(filters, operator, config)` → Sets `http_filter`\n- `removeSingleFilter(filter, config)` → Removes one filter\n- `disableConfigFilter(config)` → Clears all filters\n- `regexificationRay(value)` → Converts exact match to regex: `\"foo\"` → `\"^foo$\"`\n\nFilter types:\n\n```typescript\ninterface UiHttpFilter {\n  value: string; // The filter pattern (regex)\n  type: \"header\" | \"path\";\n}\n```\n\n### Ports\n\n- `readCurrentPorts(config)` → `number[]` - ports from `incoming.ports`\n- `updateConfigPorts(ports, config)` → Sets `incoming.ports` (and `http_filter.ports` if filters exist)\n- `readCurrentPortMapping(config)` → `[localPort, remotePort][]`\n- `updateConfigPortMapping(mappings, config)` → Sets `incoming.port_mapping`\n- `addRemoveOrUpdateMapping(remote, local, config)` → Smart mapping update\n- `getLocalPort(remotePort, config)` → Returns mapped local port or remote if no mapping\n- `removePortandMapping(remotePort, config)` → Removes port and its mapping\n- `disablePortsAndMapping(config)` → Clears both ports and mappings\n\n### JSON Export\n\n- `getConfigString(config)` → Pretty-printed JSON (removes `incoming.ports` in replace mode)\n\n## State Management\n\n### UserDataContext\n\n- `UserDataContext`: Stores boolean for `isReturning` status\n- `ConfigDataContext`: Stores current `LayerFileConfig` and setter\n- `ConfigDataContextProvider`: Wraps app with config state (initialized to `DefaultConfig`)\n\n## UI Components Needed\n\n### Core\n\n- **Wizard**: Dialog with header (title, step counter, mode badge), content area, footer (Back/Next)\n- **Panel**: Card with title, description, button → opens wizard\n\n### Form Components (from @metalbear/ui)\n\n- Button, Input, Textarea, Label\n- Select (SelectTrigger, SelectContent, SelectItem, SelectValue)\n- Tabs (TabsList, TabsTrigger, TabsContent)\n- RadioGroup (RadioGroupItem)\n- Switch, Checkbox, Separator, Badge\n- Dialog (DialogContent, DialogTitle, DialogDescription)\n- Toast (ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose)\n- Tooltip (TooltipProvider, Tooltip, TooltipTrigger, TooltipContent)\n\n### Custom (keep local)\n\n- **Card**: Simple card with CardHeader, CardTitle, CardDescription, CardContent, CardFooter\n- **Popover**: For target search dropdown (not in @metalbear/ui)\n\n## Assets\n\n- `mirrord-logo.svg` - Logo for homepage\n- `mirrord-architecture.svg` - Architecture diagram for learning steps\n- `flow-diagram.png` - Feedback loop diagram for learning steps\n\n## Key Business Rules\n\n1. **Replace Mode**: Sets `copy_target.enabled=true`, `copy_target.scale_down=true`, mode=\"steal\"\n2. **Mirror Mode**: Sets `copy_target.enabled=false`, mode=\"mirror\"\n3. **Filtering Mode**: Sets `copy_target.enabled=false`, mode=\"steal\" (allows filters)\n4. **Port Conflicts**: Local ports must be unique across all mappings\n5. **Filter Ports**: When filters exist, ports are synced to `http_filter.ports`\n6. **Target Required**: Cannot proceed to Network tab without selecting a target\n7. **Replace Mode Restrictions**: Cannot delete auto-detected ports, no `incoming.ports` in export\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# mirrord\n\n## Overview\n\nmirrord is a tool that lets developers run local processes in the context of their Kubernetes cloud environment.\n\n### Core Crates\n\n- `mirrord-layer`: gets loaded into the user's process via `LD_PRELOAD`/`DYLD_INSERT_LIBRARIES`. Intercepts libc\ncalls (files, networking, DNS, env, ...) and turns them into protocol messages sent to the intproxy.\n- `mirrord-intproxy`: a local process spawned by the CLI that bridges N layers and 1 agent. Matches requests to\nresponses, handles reconnects, and routes messages to the right feature proxy.\n- `mirrord-agent`: the in-cluster component of mirrord. Runs in the target pods' context and network namespace. Does the\nactual I/O work requested by the layers.\n- `mirrord-protocol`: defines the shared messages (`ClientMessage`, `DaemonMessage`) sent between layer/intproxy/agent.\n- `mirrord-config`: config types and validation. Used by the CLI and layer to decide what features are enabled and what\ntarget to use. Every option records the plan it needs (`oss`, `team` or `enterprise`, per its docs page) as\n`x-mirrord-plan` in the schema, as a `mirrord_config::plan::Plan`: `#[config(plan = Team)]` on `MirrordConfig`\nfields, `#[schemars(extend(\"x-mirrord-plan\" = crate::plan::Plan::Team))]` elsewhere. Nested options inherit it, except that every option under\n`feature` and every target kind needs its own; tests in `mirrord-mcp` fail on an option without one.\n- `mirrord`: the CLI that resolves configuration, creates or connects to the agent, starts the intproxy, and launches\nthe user's local process with the mirrord layer loaded.\n- `mirrord-mcp`: the MCP server behind `mirrord mcp`, which exposes mirrord to AI agents over stdio. Tools are\nregistered in its `tools` module and must be answered offline, from what is compiled into the binary. Usage is\nreported through `mirrord-analytics`, and every new tool needs a variant in its `McpTool` telemetry enum. The docs and\nskills it answers from are vendored into `mirrord/mcp/corpus` from pinned upstream commits: never edit them by hand,\nbump them with `cargo xtask corpus sync --bump` (the release PR does).\n\n## Command Reference\n\n### Compiling\n\n```bash\n# check the entire workspace at once\n# always use when a change spans multiple crates instead of checking each crate individually\nCARGO_BUILD_WARNINGS=deny cargo clippy --all-targets --all-features --keep-going\n\n# check a specific crate\n# the agent is linux only\nCARGO_BUILD_WARNINGS=deny cargo clippy -p mirrord-agent --target x86_64-unknown-linux-gnu --keep-going\n\n# layer and cli bundled with the new layer\n# use only when a fresh mirrord + layer binary is needed for testing\ncargo xtask build-cli\n```\n\nUse `--keep-going` to surface all errors at once. Use `clippy` instead of `check` to lint + compile simultaneously.\n\n### Testing\n\n```bash\n# integration tests\n# requires building the cli first with `xtask build-cli`\ncargo xtask test-integration\n\n# filtered integration tests\ncargo xtask test-integration -- outgoing_udp --nocapture\n\n# unit tests\ncargo xtask test-ut\n\n# filtered unit tests\ncargo xtask test-ut -- resolve_url_happy_path -- --nocapture\n```\n\nNever write unit tests unless explicitly asked. Run the existing tests to verify a change.\n\n### Styling\n\n```bash\n# Formatting\ncargo fmt\n```\n\n## Simplicity and Reuse\n\nmirrord is actively maintained by dozens of people, it is not a greenfield project. When adding or changing things,\nmaximize simplicity. Reuse existing abstractions and codepaths instead of introducing new ones. Every new path is\nsomething someone has to understand, maintain, and keep compatible.\n\nAvoid extracting trivial, self-contained logic into a function used only once. Keep it near its point of use when the\nhelper would merely add indirection or exist to make a tiny test possible. Extract a function when it is reused or hides\nnon-obvious details that would distract from the surrounding flow. Test meaningful behavior rather than trivial\nwrappers around a library API.\n\n## Comments and Documentation\n\nDon't write comments explaining what code does, the code should speak for itself. Instead, focus on _why_ something\nexists: doc comments that explain the problem a function or struct solves and how it fits into the bigger picture are\nfar more valuable than ones that restate the type signature. Module-level doc comments that give a high-level overview\nof what a file is responsible for are also very helpful, as they give readers the context to understand the code below.\nmirrord has a lot of moving pieces and stability is critical, so document tricky or non-obvious behavior clearly.\n\nWrite comments for readers of the resulting code, not reviewers of the patch. Comments must stand alone after merge and\ndescribe the current behavior, intent, invariant, or non-obvious tradeoff. Don't narrate the edit or use patch-relative\nlanguage such as `the existing implementation`, `the new approach`, `now`, `previously`, `this change`, or\n`we added/removed`. Include historical context only when it is necessary to explain why the current code deliberately\ndiffers from an otherwise-obvious alternative.\n\n## Stack Usage\n\nThe CLI polls its whole runtime on the main thread, and on Windows that thread only gets the `/STACK` linked in\n`mirrord/cli/build.rs`. Debug builds are hit hardest: a function's frame keeps a slot for every future it builds\nbefore awaiting it, so one `match` with a large future per arm pays for all of them.\n\n- Put `#[mirrord_macros::boxed_future]` (above `#[tracing::instrument]`) on an `async fn` with a large future, such as\n  a subcommand or a connection step: it builds its future on the heap, and callers keep writing `f(..).await`.\n  `Box::pin(f(..))` and `.boxed()` don't help in a debug build, since `f(..)` is still built in the caller's frame first.\n- On a stack overflow, the Windows CLI prints every frame with its size, largest first. Windows CI runs\n  `scripts/win_stack_check.ps1`, which fails when the CLI outgrows its budget and shows that report.\n- `scripts/win_stack_report.ps1` measures peak stack and large frames locally.\n\n## Style Guideline\n\n- Keep imports at file top (no function-local `use`).\n- Prefer `to_owned` for `&str` → `String`.\n- Always use `foo.rs` instead of `foo/mod.rs` for module roots.\n- Run styling commands after every edit.\n","isInternal":false,"tokens":1491,"sizeBytes":6302},{"name":"package.json","path":"packages/monitor/package.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/monitor/package.json","title":"session-monitor-frontend","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"session-monitor-frontend\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Session monitor feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"typecheck\": \"tsc -b\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"lucide-react\": \"^0.577.0\",\n    \"posthog-js\": \"^1.364.6\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","frontmatter":{"name":"session-monitor-frontend","private":true,"version":"0.1.0","type":"module","description":"Session monitor feature of the merged mirrord UI (built via packages/ui).","scripts":{"lint":"eslint src","lint:fix":"eslint src --fix","format":"prettier --write src","format:check":"prettier --check src","typecheck":"tsc -b","test":"vitest","test:run":"vitest run"},"dependencies":{"@metalbear/ui":"^0.4.0","lucide-react":"^0.577.0","posthog-js":"^1.364.6","react":"^18.3.1","react-dom":"^18.3.1"},"devDependencies":{"@eslint/js":"^9.39.2","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","eslint":"^9.39.2","eslint-config-prettier":"^10.1.8","prettier":"^3.8.1","tailwindcss":"^3.4.16","typescript":"^5.7.0","typescript-eslint":"^8.53.1","vite":"^6.0.0","vitest":"^2.1.8"}},"isInternal":false,"tokens":355,"sizeBytes":962},{"name":"tsconfig.json","path":"packages/monitor/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/monitor/tsconfig.json","title":"Monitor Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.ts\", \"src/**/*.test.tsx\"]\n}\n","frontmatter":{"extends":"@metalbear/ui/tsconfig.base.json","compilerOptions":{"target":"ES2020","useDefineForClassFields":true,"lib":["ES2020","DOM","DOM.Iterable"],"module":"ESNext","moduleResolution":"bundler","allowImportingTsExtensions":true,"moduleDetection":"force","noEmit":true,"jsx":"react-jsx"},"include":["src"],"exclude":["src/**/*.test.ts","src/**/*.test.tsx"]},"isInternal":false,"tokens":135,"sizeBytes":439},{"name":"package.json","path":"packages/ui/package.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/ui/package.json","title":"mirrord-ui","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"mirrord-ui\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\"\n  },\n  \"dependencies\": {\n    \"@fontsource/poppins\": \"^5.2.7\",\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.577.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"autoprefixer\": \"^10.4.20\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"postcss\": \"^8.4.49\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n","frontmatter":{"name":"mirrord-ui","private":true,"version":"0.1.0","type":"module","scripts":{"dev":"vite","build":"vite build","preview":"vite preview","typecheck":"tsc --noEmit","lint":"eslint src","lint:fix":"eslint src --fix","format":"prettier --write src","format:check":"prettier --check src"},"dependencies":{"@fontsource/poppins":"^5.2.7","@metalbear/ui":"^0.4.0","@tanstack/react-query":"^5.56.2","lucide-react":"^0.577.0","react":"^18.3.1","react-dom":"^18.3.1"},"devDependencies":{"@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@vitejs/plugin-react":"^4.3.4","autoprefixer":"^10.4.20","eslint":"^9.39.2","eslint-config-prettier":"^10.1.8","postcss":"^8.4.49","prettier":"^3.8.1","tailwindcss":"^3.4.16","typescript":"^5.7.0","typescript-eslint":"^8.53.1","vite":"^6.0.0"}},"isInternal":false,"tokens":372,"sizeBytes":975},{"name":"tsconfig.json","path":"packages/ui/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/ui/tsconfig.json","title":"Ui Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"paths\": {\n      \"@mirrord/monitor/theme\": [\"../monitor/src/theme.ts\"],\n      \"@mirrord/monitor/events\": [\"../monitor/src/events.tsx\"],\n      \"@mirrord/monitor\": [\"../monitor/src/index.tsx\"],\n      \"@mirrord/wizard\": [\"../wizard/src/index.tsx\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n","frontmatter":{"extends":"@metalbear/ui/tsconfig.base.json","compilerOptions":{"target":"ES2020","useDefineForClassFields":true,"lib":["ES2020","DOM","DOM.Iterable"],"module":"ESNext","moduleResolution":"bundler","allowImportingTsExtensions":true,"moduleDetection":"force","noEmit":true,"jsx":"react-jsx","paths":{"@mirrord/monitor/theme":["../monitor/src/theme.ts"],"@mirrord/monitor/events":["../monitor/src/events.tsx"],"@mirrord/monitor":["../monitor/src/index.tsx"],"@mirrord/wizard":["../wizard/src/index.tsx"]}},"include":["src"]},"isInternal":false,"tokens":190,"sizeBytes":639},{"name":"BUSINESS_LOGIC.md","path":"packages/wizard/BUSINESS_LOGIC.md","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/wizard/BUSINESS_LOGIC.md","title":"Wizard Skill","category":"anthropic-skill","format":"markdown","content":"# mirrord Wizard Frontend - Business Logic\n\n## Overview\n\nThe wizard frontend is a React application that helps users create `mirrord.json` configuration files through a guided wizard interface. It connects to a backend API to fetch Kubernetes cluster information.\n\n## Application Flow\n\n### 1. Entry Point (App.tsx → Homepage.tsx)\n\n1. App checks if user is \"returning\" via API call to `/api/v1/is-returning`\n2. Based on response, shows either:\n   - **New User**: `HomepageNewUser` - Welcome message + two panels (Learn First / Skip to Config)\n   - **Returning User**: `HomepageReturning` - Welcome back + two panels (Create Config / Learn)\n\n### 2. Homepage Panels\n\nEach homepage has two clickable panels that open different wizard flows:\n\n**New User:**\n\n- \"Learn About mirrord First\" → IntroStep + 6 Learning Steps + BoilerplateStep + ConfigStep\n- \"Skip to Configuration\" → BoilerplateStep + ConfigStep\n\n**Returning User:**\n\n- \"Create Configuration\" → BoilerplateStep + ConfigStep\n- \"Learn About mirrord\" → 6 Learning Steps + BoilerplateStep + ConfigStep\n\n### 3. Wizard Steps\n\n#### Step: BoilerplateStep\n\nUser selects one of three modes:\n\n- **Filtering Mode** (steal): Selective traffic stealing with HTTP header/path filters\n- **Mirror Mode**: Copy traffic without disrupting remote service\n- **Replace Mode**: Completely substitute remote service (copy_target + scale_down)\n\n#### Step: ConfigStep (ConfigTabs)\n\nThree tabs:\n\n1. **Target Tab**: Select namespace, target type, and specific target from K8s cluster\n2. **Network Tab**: Configure incoming traffic, filters, and port mappings\n3. **Export Tab**: View JSON, copy to clipboard, or download file\n\n## API Routes\n\n```typescript\nconst ALL_API_ROUTES = {\n  isReturning: \"/api/v1/is-returning\",\n  clusterDetails: \"/api/v1/cluster-details\", // Returns { namespaces: string[], target_types: string[] }\n  targets: (namespace: string, targetType?: string) =>\n    \"/api/v1/namespace/{namespace}/targets?target_type={targetType}\",\n  // Returns Target[] where Target = { target_path, target_namespace, detected_ports }\n};\n```\n\n## Config Data Structure\n\n### Default Config\n\n```typescript\nconst DefaultConfig: LayerFileConfig = {\n  feature: {\n    network: {\n      incoming: { mode: \"mirror\" },\n      outgoing: true,\n    },\n    fs: \"read\",\n    env: true,\n  },\n};\n```\n\n### Key Config Sections\n\n1. **target**: `{ path: \"deployment/name\", namespace: \"default\" }`\n2. **feature.network.incoming.mode**: `\"mirror\"` | `\"steal\"`\n3. **feature.network.incoming.ports**: `number[]` - ports to intercept\n4. **feature.network.incoming.port_mapping**: `[localPort, remotePort][]`\n5. **feature.network.incoming.http_filter**: Header/path filters for selective stealing\n6. **feature.copy_target**: `{ enabled: boolean, scale_down: boolean }` - for Replace mode\n\n## Config Manipulation Functions (JsonUtils.tsx)\n\n### Mode/Boilerplate\n\n- `readBoilerplateType(config)` → `\"steal\"` | `\"mirror\"` | `\"replace\"` | `\"custom\"`\n- `updateConfigMode(mode, config)` → Sets `incoming.mode`\n- `updateConfigCopyTarget(enabled, scaleDown, config)` → Sets `copy_target`\n\n### Target\n\n- `readCurrentTargetDetails(config)` → `{ type: string, name?: string }`\n- `updateConfigTarget(config, targetPath, namespace)` → Sets `target`\n\n### Incoming Network\n\n- `readIncoming(config)` → Returns entire `network.incoming` section\n- `updateIncoming(config, newIncoming)` → Replaces `network.incoming`\n\n### HTTP Filters\n\n- `readCurrentFilters(config)` → `{ filters: UiHttpFilter[], operator: \"any\"|\"all\"|null }`\n- `updateConfigFilter(filters, operator, config)` → Sets `http_filter`\n- `removeSingleFilter(filter, config)` → Removes one filter\n- `disableConfigFilter(config)` → Clears all filters\n- `regexificationRay(value)` → Converts exact match to regex: `\"foo\"` → `\"^foo$\"`\n\nFilter types:\n\n```typescript\ninterface UiHttpFilter {\n  value: string; // The filter pattern (regex)\n  type: \"header\" | \"path\";\n}\n```\n\n### Ports\n\n- `readCurrentPorts(config)` → `number[]` - ports from `incoming.ports`\n- `updateConfigPorts(ports, config)` → Sets `incoming.ports` (and `http_filter.ports` if filters exist)\n- `readCurrentPortMapping(config)` → `[localPort, remotePort][]`\n- `updateConfigPortMapping(mappings, config)` → Sets `incoming.port_mapping`\n- `addRemoveOrUpdateMapping(remote, local, config)` → Smart mapping update\n- `getLocalPort(remotePort, config)` → Returns mapped local port or remote if no mapping\n- `removePortandMapping(remotePort, config)` → Removes port and its mapping\n- `disablePortsAndMapping(config)` → Clears both ports and mappings\n\n### JSON Export\n\n- `getConfigString(config)` → Pretty-printed JSON (removes `incoming.ports` in replace mode)\n\n## State Management\n\n### UserDataContext\n\n- `UserDataContext`: Stores boolean for `isReturning` status\n- `ConfigDataContext`: Stores current `LayerFileConfig` and setter\n- `ConfigDataContextProvider`: Wraps app with config state (initialized to `DefaultConfig`)\n\n## UI Components Needed\n\n### Core\n\n- **Wizard**: Dialog with header (title, step counter, mode badge), content area, footer (Back/Next)\n- **Panel**: Card with title, description, button → opens wizard\n\n### Form Components (from @metalbear/ui)\n\n- Button, Input, Textarea, Label\n- Select (SelectTrigger, SelectContent, SelectItem, SelectValue)\n- Tabs (TabsList, TabsTrigger, TabsContent)\n- RadioGroup (RadioGroupItem)\n- Switch, Checkbox, Separator, Badge\n- Dialog (DialogContent, DialogTitle, DialogDescription)\n- Toast (ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose)\n- Tooltip (TooltipProvider, Tooltip, TooltipTrigger, TooltipContent)\n\n### Custom (keep local)\n\n- **Card**: Simple card with CardHeader, CardTitle, CardDescription, CardContent, CardFooter\n- **Popover**: For target search dropdown (not in @metalbear/ui)\n\n## Assets\n\n- `mirrord-logo.svg` - Logo for homepage\n- `mirrord-architecture.svg` - Architecture diagram for learning steps\n- `flow-diagram.png` - Feedback loop diagram for learning steps\n\n## Key Business Rules\n\n1. **Replace Mode**: Sets `copy_target.enabled=true`, `copy_target.scale_down=true`, mode=\"steal\"\n2. **Mirror Mode**: Sets `copy_target.enabled=false`, mode=\"mirror\"\n3. **Filtering Mode**: Sets `copy_target.enabled=false`, mode=\"steal\" (allows filters)\n4. **Port Conflicts**: Local ports must be unique across all mappings\n5. **Filter Ports**: When filters exist, ports are synced to `http_filter.ports`\n6. **Target Required**: Cannot proceed to Network tab without selecting a target\n7. **Replace Mode Restrictions**: Cannot delete auto-detected ports, no `incoming.ports` in export\n","isInternal":false,"tokens":1590,"sizeBytes":6623},{"name":"package.json","path":"packages/wizard/package.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/wizard/package.json","title":"mirrord-wizard","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"mirrord-wizard\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Config wizard feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"typecheck\": \"tsc\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"prepare\": \"cd ../.. && husky packages/wizard/.husky\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.469.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"eslint --fix\",\n      \"prettier --write\"\n    ],\n    \"*.{js,jsx,json,css,md}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.1.0\",\n    \"@types/node\": \"^22.5.5\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"husky\": \"^9.1.7\",\n    \"jsdom\": \"^25.0.1\",\n    \"lint-staged\": \"^16.2.7\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.17\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n","frontmatter":{"name":"mirrord-wizard","private":true,"version":"0.1.0","type":"module","description":"Config wizard feature of the merged mirrord UI (built via packages/ui).","scripts":{"typecheck":"tsc","lint":"eslint src","lint:fix":"eslint src --fix","format":"prettier --write src","format:check":"prettier --check src","test":"vitest","test:run":"vitest run","test:coverage":"vitest run --coverage","prepare":"cd ../.. && husky packages/wizard/.husky"},"dependencies":{"@metalbear/ui":"^0.4.0","@tanstack/react-query":"^5.56.2","lucide-react":"^0.469.0","react":"^18.3.1","react-dom":"^18.3.1"},"lint-staged":{"*.{ts,tsx}":["eslint --fix","prettier --write"],"*.{js,jsx,json,css,md}":["prettier --write"]},"devDependencies":{"@eslint/js":"^9.39.2","@testing-library/jest-dom":"^6.6.3","@testing-library/react":"^16.1.0","@types/node":"^22.5.5","@types/react":"^18.3.3","@types/react-dom":"^18.3.0","@vitejs/plugin-react-swc":"^3.5.0","eslint":"^9.39.2","eslint-config-prettier":"^10.1.8","husky":"^9.1.7","jsdom":"^25.0.1","lint-staged":"^16.2.7","prettier":"^3.8.1","tailwindcss":"^3.4.17","typescript":"^5.7.0","typescript-eslint":"^8.53.1","vite":"^6.0.0","vitest":"^2.1.8"}},"isInternal":false,"tokens":538,"sizeBytes":1455},{"name":"tsconfig.json","path":"packages/wizard/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/metalbear-co/mirrord/HEAD/packages/wizard/tsconfig.json","title":"Wizard Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.tsx\", \"src/**/*.test.ts\"]\n}\n","frontmatter":{"extends":"@metalbear/ui/tsconfig.base.json","compilerOptions":{"target":"ES2020","useDefineForClassFields":true,"lib":["ES2020","DOM","DOM.Iterable"],"module":"ESNext","moduleResolution":"bundler","allowImportingTsExtensions":true,"noEmit":true,"jsx":"react-jsx","baseUrl":".","paths":{"@/*":["./src/*"]}},"include":["src"],"exclude":["src/**/*.test.tsx","src/**/*.test.ts"]},"isInternal":false,"tokens":149,"sizeBytes":474}],"systemPromptSnippet":"<yakaai_skills repo=\"metalbear-co/mirrord\">\n<!-- File: AGENTS.md (Tokens: ~1491 | Category: root-instruction) -->\n# mirrord\n\n## Overview\n\nmirrord is a tool that lets developers run local processes in the context of their Kubernetes cloud environment.\n\n### Core Crates\n\n- `mirrord-layer`: gets loaded into the user's process via `LD_PRELOAD`/`DYLD_INSERT_LIBRARIES`. Intercepts libc\ncalls (files, networking, DNS, env, ...) and turns them into protocol messages sent to the intproxy.\n- `mirrord-intproxy`: a local process spawned by the CLI that bridges N layers and 1 agent. Matches requests to\nresponses, handles reconnects, and routes messages to the right feature proxy.\n- `mirrord-agent`: the in-cluster component of mirrord. Runs in the target pods' context and network namespace. Does the\nactual I/O work requested by the layers.\n- `mirrord-protocol`: defines the shared messages (`ClientMessage`, `DaemonMessage`) sent between layer/intproxy/agent.\n- `mirrord-config`: config types and validation. Used by the CLI and layer to decide what features are enabled and what\ntarget to use. Every option records the plan it needs (`oss`, `team` or `enterprise`, per its docs page) as\n`x-mirrord-plan` in the schema, as a `mirrord_config::plan::Plan`: `#[config(plan = Team)]` on `MirrordConfig`\nfields, `#[schemars(extend(\"x-mirrord-plan\" = crate::plan::Plan::Team))]` elsewhere. Nested options inherit it, except that every option under\n`feature` and every target kind needs its own; tests in `mirrord-mcp` fail on an option without one.\n- `mirrord`: the CLI that resolves configuration, creates or connects to the agent, starts the intproxy, and launches\nthe user's local process with the mirrord layer loaded.\n- `mirrord-mcp`: the MCP server behind `mirrord mcp`, which exposes mirrord to AI agents over stdio. Tools are\nregistered in its `tools` module and must be answered offline, from what is compiled into the binary. Usage is\nreported through `mirrord-analytics`, and every new tool needs a variant in its `McpTool` telemetry enum. The docs and\nskills it answers from are vendored into `mirrord/mcp/corpus` from pinned upstream commits: never edit them by hand,\nbump them with `cargo xtask corpus sync --bump` (the release PR does).\n\n## Command Reference\n\n### Compiling\n\n```bash\n# check the entire workspace at once\n# always use when a change spans multiple crates instead of checking each crate individually\nCARGO_BUILD_WARNINGS=deny cargo clippy --all-targets --all-features --keep-going\n\n# check a specific crate\n# the agent is linux only\nCARGO_BUILD_WARNINGS=deny cargo clippy -p mirrord-agent --target x86_64-unknown-linux-gnu --keep-going\n\n# layer and cli bundled with the new layer\n# use only when a fresh mirrord + layer binary is needed for testing\ncargo xtask build-cli\n```\n\nUse `--keep-going` to surface all errors at once. Use `clippy` instead of `check` to lint + compile simultaneously.\n\n### Testing\n\n```bash\n# integration tests\n# requires building the cli first with `xtask build-cli`\ncargo xtask test-integration\n\n# filtered integration tests\ncargo xtask test-integration -- outgoing_udp --nocapture\n\n# unit tests\ncargo xtask test-ut\n\n# filtered unit tests\ncargo xtask test-ut -- resolve_url_happy_path -- --nocapture\n```\n\nNever write unit tests unless explicitly asked. Run the existing tests to verify a change.\n\n### Styling\n\n```bash\n# Formatting\ncargo fmt\n```\n\n## Simplicity and Reuse\n\nmirrord is actively maintained by dozens of people, it is not a greenfield project. When adding or changing things,\nmaximize simplicity. Reuse existing abstractions and codepaths instead of introducing new ones. Every new path is\nsomething someone has to understand, maintain, and keep compatible.\n\nAvoid extracting trivial, self-contained logic into a function used only once. Keep it near its point of use when the\nhelper would merely add indirection or exist to make a tiny test possible. Extract a function when it is reused or hides\nnon-obvious details that would distract from the surrounding flow. Test meaningful behavior rather than trivial\nwrappers around a library API.\n\n## Comments and Documentation\n\nDon't write comments explaining what code does, the code should speak for itself. Instead, focus on _why_ something\nexists: doc comments that explain the problem a function or struct solves and how it fits into the bigger picture are\nfar more valuable than ones that restate the type signature. Module-level doc comments that give a high-level overview\nof what a file is responsible for are also very helpful, as they give readers the context to understand the code below.\nmirrord has a lot of moving pieces and stability is critical, so document tricky or non-obvious behavior clearly.\n\nWrite comments for readers of the resulting code, not reviewers of the patch. Comments must stand alone after merge and\ndescribe the current behavior, intent, invariant, or non-obvious tradeoff. Don't narrate the edit or use patch-relative\nlanguage such as `the existing implementation`, `the new approach`, `now`, `previously`, `this change`, or\n`we added/removed`. Include historical context only when it is necessary to explain why the current code deliberately\ndiffers from an otherwise-obvious alternative.\n\n## Stack Usage\n\nThe CLI polls its whole runtime on the main thread, and on Windows that thread only gets the `/STACK` linked in\n`mirrord/cli/build.rs`. Debug builds are hit hardest: a function's frame keeps a slot for every future it builds\nbefore awaiting it, so one `match` with a large future per arm pays for all of them.\n\n- Put `#[mirrord_macros::boxed_future]` (above `#[tracing::instrument]`) on an `async fn` with a large future, such as\n  a subcommand or a connection step: it builds its future on the heap, and callers keep writing `f(..).await`.\n  `Box::pin(f(..))` and `.boxed()` don't help in a debug build, since `f(..)` is still built in the caller's frame first.\n- On a stack overflow, the Windows CLI prints every frame with its size, largest first. Windows CI runs\n  `scripts/win_stack_check.ps1`, which fails when the CLI outgrows its budget and shows that report.\n- `scripts/win_stack_report.ps1` measures peak stack and large frames locally.\n\n## Style Guideline\n\n- Keep imports at file top (no function-local `use`).\n- Prefer `to_owned` for `&str` → `String`.\n- Always use `foo.rs` instead of `foo/mod.rs` for module roots.\n- Run styling commands after every edit.\n\n<!-- File: packages/monitor/package.json (Tokens: ~355 | Category: anthropic-skill) -->\n{\n  \"name\": \"session-monitor-frontend\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Session monitor feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"typecheck\": \"tsc -b\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"lucide-react\": \"^0.577.0\",\n    \"posthog-js\": \"^1.364.6\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n\n<!-- File: packages/monitor/tsconfig.json (Tokens: ~135 | Category: anthropic-skill) -->\n{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.ts\", \"src/**/*.test.tsx\"]\n}\n\n<!-- File: packages/ui/package.json (Tokens: ~372 | Category: anthropic-skill) -->\n{\n  \"name\": \"mirrord-ui\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\"\n  },\n  \"dependencies\": {\n    \"@fontsource/poppins\": \"^5.2.7\",\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.577.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.3.12\",\n    \"@types/react-dom\": \"^18.3.1\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"autoprefixer\": \"^10.4.20\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"postcss\": \"^8.4.49\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.16\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n\n<!-- File: packages/ui/tsconfig.json (Tokens: ~190 | Category: anthropic-skill) -->\n{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"paths\": {\n      \"@mirrord/monitor/theme\": [\"../monitor/src/theme.ts\"],\n      \"@mirrord/monitor/events\": [\"../monitor/src/events.tsx\"],\n      \"@mirrord/monitor\": [\"../monitor/src/index.tsx\"],\n      \"@mirrord/wizard\": [\"../wizard/src/index.tsx\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n\n<!-- File: packages/wizard/BUSINESS_LOGIC.md (Tokens: ~1590 | Category: anthropic-skill) -->\n# mirrord Wizard Frontend - Business Logic\n\n## Overview\n\nThe wizard frontend is a React application that helps users create `mirrord.json` configuration files through a guided wizard interface. It connects to a backend API to fetch Kubernetes cluster information.\n\n## Application Flow\n\n### 1. Entry Point (App.tsx → Homepage.tsx)\n\n1. App checks if user is \"returning\" via API call to `/api/v1/is-returning`\n2. Based on response, shows either:\n   - **New User**: `HomepageNewUser` - Welcome message + two panels (Learn First / Skip to Config)\n   - **Returning User**: `HomepageReturning` - Welcome back + two panels (Create Config / Learn)\n\n### 2. Homepage Panels\n\nEach homepage has two clickable panels that open different wizard flows:\n\n**New User:**\n\n- \"Learn About mirrord First\" → IntroStep + 6 Learning Steps + BoilerplateStep + ConfigStep\n- \"Skip to Configuration\" → BoilerplateStep + ConfigStep\n\n**Returning User:**\n\n- \"Create Configuration\" → BoilerplateStep + ConfigStep\n- \"Learn About mirrord\" → 6 Learning Steps + BoilerplateStep + ConfigStep\n\n### 3. Wizard Steps\n\n#### Step: BoilerplateStep\n\nUser selects one of three modes:\n\n- **Filtering Mode** (steal): Selective traffic stealing with HTTP header/path filters\n- **Mirror Mode**: Copy traffic without disrupting remote service\n- **Replace Mode**: Completely substitute remote service (copy_target + scale_down)\n\n#### Step: ConfigStep (ConfigTabs)\n\nThree tabs:\n\n1. **Target Tab**: Select namespace, target type, and specific target from K8s cluster\n2. **Network Tab**: Configure incoming traffic, filters, and port mappings\n3. **Export Tab**: View JSON, copy to clipboard, or download file\n\n## API Routes\n\n```typescript\nconst ALL_API_ROUTES = {\n  isReturning: \"/api/v1/is-returning\",\n  clusterDetails: \"/api/v1/cluster-details\", // Returns { namespaces: string[], target_types: string[] }\n  targets: (namespace: string, targetType?: string) =>\n    \"/api/v1/namespace/{namespace}/targets?target_type={targetType}\",\n  // Returns Target[] where Target = { target_path, target_namespace, detected_ports }\n};\n```\n\n## Config Data Structure\n\n### Default Config\n\n```typescript\nconst DefaultConfig: LayerFileConfig = {\n  feature: {\n    network: {\n      incoming: { mode: \"mirror\" },\n      outgoing: true,\n    },\n    fs: \"read\",\n    env: true,\n  },\n};\n```\n\n### Key Config Sections\n\n1. **target**: `{ path: \"deployment/name\", namespace: \"default\" }`\n2. **feature.network.incoming.mode**: `\"mirror\"` | `\"steal\"`\n3. **feature.network.incoming.ports**: `number[]` - ports to intercept\n4. **feature.network.incoming.port_mapping**: `[localPort, remotePort][]`\n5. **feature.network.incoming.http_filter**: Header/path filters for selective stealing\n6. **feature.copy_target**: `{ enabled: boolean, scale_down: boolean }` - for Replace mode\n\n## Config Manipulation Functions (JsonUtils.tsx)\n\n### Mode/Boilerplate\n\n- `readBoilerplateType(config)` → `\"steal\"` | `\"mirror\"` | `\"replace\"` | `\"custom\"`\n- `updateConfigMode(mode, config)` → Sets `incoming.mode`\n- `updateConfigCopyTarget(enabled, scaleDown, config)` → Sets `copy_target`\n\n### Target\n\n- `readCurrentTargetDetails(config)` → `{ type: string, name?: string }`\n- `updateConfigTarget(config, targetPath, namespace)` → Sets `target`\n\n### Incoming Network\n\n- `readIncoming(config)` → Returns entire `network.incoming` section\n- `updateIncoming(config, newIncoming)` → Replaces `network.incoming`\n\n### HTTP Filters\n\n- `readCurrentFilters(config)` → `{ filters: UiHttpFilter[], operator: \"any\"|\"all\"|null }`\n- `updateConfigFilter(filters, operator, config)` → Sets `http_filter`\n- `removeSingleFilter(filter, config)` → Removes one filter\n- `disableConfigFilter(config)` → Clears all filters\n- `regexificationRay(value)` → Converts exact match to regex: `\"foo\"` → `\"^foo$\"`\n\nFilter types:\n\n```typescript\ninterface UiHttpFilter {\n  value: string; // The filter pattern (regex)\n  type: \"header\" | \"path\";\n}\n```\n\n### Ports\n\n- `readCurrentPorts(config)` → `number[]` - ports from `incoming.ports`\n- `updateConfigPorts(ports, config)` → Sets `incoming.ports` (and `http_filter.ports` if filters exist)\n- `readCurrentPortMapping(config)` → `[localPort, remotePort][]`\n- `updateConfigPortMapping(mappings, config)` → Sets `incoming.port_mapping`\n- `addRemoveOrUpdateMapping(remote, local, config)` → Smart mapping update\n- `getLocalPort(remotePort, config)` → Returns mapped local port or remote if no mapping\n- `removePortandMapping(remotePort, config)` → Removes port and its mapping\n- `disablePortsAndMapping(config)` → Clears both ports and mappings\n\n### JSON Export\n\n- `getConfigString(config)` → Pretty-printed JSON (removes `incoming.ports` in replace mode)\n\n## State Management\n\n### UserDataContext\n\n- `UserDataContext`: Stores boolean for `isReturning` status\n- `ConfigDataContext`: Stores current `LayerFileConfig` and setter\n- `ConfigDataContextProvider`: Wraps app with config state (initialized to `DefaultConfig`)\n\n## UI Components Needed\n\n### Core\n\n- **Wizard**: Dialog with header (title, step counter, mode badge), content area, footer (Back/Next)\n- **Panel**: Card with title, description, button → opens wizard\n\n### Form Components (from @metalbear/ui)\n\n- Button, Input, Textarea, Label\n- Select (SelectTrigger, SelectContent, SelectItem, SelectValue)\n- Tabs (TabsList, TabsTrigger, TabsContent)\n- RadioGroup (RadioGroupItem)\n- Switch, Checkbox, Separator, Badge\n- Dialog (DialogContent, DialogTitle, DialogDescription)\n- Toast (ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose)\n- Tooltip (TooltipProvider, Tooltip, TooltipTrigger, TooltipContent)\n\n### Custom (keep local)\n\n- **Card**: Simple card with CardHeader, CardTitle, CardDescription, CardContent, CardFooter\n- **Popover**: For target search dropdown (not in @metalbear/ui)\n\n## Assets\n\n- `mirrord-logo.svg` - Logo for homepage\n- `mirrord-architecture.svg` - Architecture diagram for learning steps\n- `flow-diagram.png` - Feedback loop diagram for learning steps\n\n## Key Business Rules\n\n1. **Replace Mode**: Sets `copy_target.enabled=true`, `copy_target.scale_down=true`, mode=\"steal\"\n2. **Mirror Mode**: Sets `copy_target.enabled=false`, mode=\"mirror\"\n3. **Filtering Mode**: Sets `copy_target.enabled=false`, mode=\"steal\" (allows filters)\n4. **Port Conflicts**: Local ports must be unique across all mappings\n5. **Filter Ports**: When filters exist, ports are synced to `http_filter.ports`\n6. **Target Required**: Cannot proceed to Network tab without selecting a target\n7. **Replace Mode Restrictions**: Cannot delete auto-detected ports, no `incoming.ports` in export\n\n<!-- File: packages/wizard/package.json (Tokens: ~538 | Category: anthropic-skill) -->\n{\n  \"name\": \"mirrord-wizard\",\n  \"private\": true,\n  \"version\": \"0.1.0\",\n  \"type\": \"module\",\n  \"description\": \"Config wizard feature of the merged mirrord UI (built via packages/ui).\",\n  \"scripts\": {\n    \"typecheck\": \"tsc\",\n    \"lint\": \"eslint src\",\n    \"lint:fix\": \"eslint src --fix\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"test\": \"vitest\",\n    \"test:run\": \"vitest run\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"prepare\": \"cd ../.. && husky packages/wizard/.husky\"\n  },\n  \"dependencies\": {\n    \"@metalbear/ui\": \"^0.4.0\",\n    \"@tanstack/react-query\": \"^5.56.2\",\n    \"lucide-react\": \"^0.469.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"eslint --fix\",\n      \"prettier --write\"\n    ],\n    \"*.{js,jsx,json,css,md}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.2\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.1.0\",\n    \"@types/node\": \"^22.5.5\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"husky\": \"^9.1.7\",\n    \"jsdom\": \"^25.0.1\",\n    \"lint-staged\": \"^16.2.7\",\n    \"prettier\": \"^3.8.1\",\n    \"tailwindcss\": \"^3.4.17\",\n    \"typescript\": \"^5.7.0\",\n    \"typescript-eslint\": \"^8.53.1\",\n    \"vite\": \"^6.0.0\",\n    \"vitest\": \"^2.1.8\"\n  }\n}\n\n<!-- File: packages/wizard/tsconfig.json (Tokens: ~149 | Category: anthropic-skill) -->\n{\n  \"extends\": \"@metalbear/ui/tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"src/**/*.test.tsx\", \"src/**/*.test.ts\"]\n}\n</yakaai_skills>"}