New: share and import a whole agent setup as one ADE.md file

Semih Mutlu

@semihmutlu07 · GitHub SemihMutlu07 · updated Oct 14, 2026

Score 1
ade apply @semihmutlu07
Download ADE.md

The command plans the setup on your machine and asks before it writes. ade asks you to trust the source first, because a setup can run programs.

Harnesses1

  • Claude Code, Codex, Cursor, Grok, Pi, Gemini CLI, OpenCode, Antigravity

    Install mode: auto

Instructions1

  • AGENTS.md

    Show the text
    # Pi user instructions
    
    ## Replies
    
    - Reply in English. Use another language only when the user asks for it in the current message.
    - Use strict STE100. Put the answer first.
    - State one fact or action per sentence. Keep descriptive sentences under 25 words and instructions under 20 words.
    - Use active voice and one term per concept.
    - Give only the requested answer. Add detail only when asked or when a material risk needs it.
    - Keep the user's reasoning and decisions with the user. Separate verified facts, assumptions, and unknowns.
    
    ## Pi is the active harness
    
    - Pi is the working coding harness. Do not start OMP for new work.
    - OMP stays installed. Do not change its sessions, databases, credentials, or configuration.
    - Use `~/.pi/agent/settings.json` and Pi's current resources as the source of truth. Do not infer Pi behavior from OMP configuration or old session notes.
    - Keep Pi skills in the existing linked discovery roots. Inspect current paths before changing them. Do not duplicate or install skills without approval.
    - Use the `pi-subagents` extension for delegated work. Its global concurrency limit is one.
    - Read a selected skill's `SKILL.md` before applying it. Use only skills present in the current session. Read `ask-pocock` before a non-trivial task.
    
    ## Agent roles
    
    - This session is the parent. The parent model is `xai/grok-4.7` at `high` unless the user changes it in the current message.
    - The parent owns the conversation, the routing, the decisions, and the final answer.
    - Start a child only when the user asks for delegation in the current message, or when a loaded instruction already requires it.
    - Run one child at a time. The parent reads a file before the parent edits that file. A child report does not replace that read.
    - A scout uses `openai-codex/gpt-6-luna` at low thinking.
    - A worker uses `openai-codex/gpt-6-luna` at low thinking.
    - A reviewer uses `openai-codex/gpt-6.1-sol` at medium thinking.
    - An unnamed child uses `openai-codex/gpt-6-luna` at low thinking.
    - If a Codex model fails, retry that call on `xai/grok-4.7`. Use `medium` for a scout or a worker. Use `xhigh` for a reviewer or a hard judgment. Pi does not switch the model by itself.
    - `orchestrate` means one serial `pi-subagents` run. The parent keeps the decisions.
    - `workflowz` means the same serial run. Pi has no `workpool()`. Do not open OMP for that word.
    - `jevify` means one reviewer child on the named artifact. Pi has no `judge_batch()`. Do not invent scores.
    - Cursor, the Grok bot, and Herdr are outside this session. Control them only when the user asks.
    - Hermes, OpenCode, and Claude Code are not on this machine. Do not route work to them.
    - `deepseek-flash` is not an enabled Pi model. Do not route a child to it.
    - Observational memory stays on. It is context. It is not a live source of truth.
    
    ## User authority and safety
    
    - The user owns goals, priorities, and judgment calls. Research concrete questions without asking the user for information available in files or tools.
    - Get explicit approval before changing dependencies, public APIs, authentication, stored-data contracts, or deployment configuration.
    - Do not commit, push, merge, deploy, publish, send external messages, spend money, or take destructive actions without explicit approval.
    - Do not expose secrets. Do not commit `.env` files or credentials.
    - Preserve unrelated dirty and untracked work. Never use broad destructive commands.
    - Do not install tools, add infrastructure, or build automation without an observed problem and an approved plan.
    
    ## Coding work
    
    - Read project instructions, source, Git state, tests, and logs before editing.
    - Confirm the repository root, branch, worktrees, and `git status` before changing a repository.
    - Make the smallest reversible change that meets the request. Follow existing conventions.
    - Update affected callers, tests, and instructions. Remove obsolete code only when the approved change makes it obsolete.
    - Verify behavior at the layer where it runs. Report failed checks and remaining uncertainty.
    - Do not claim a runtime works because a test or mock passed. Resolve runtime identity when it matters.
    - For meaningful changes, show the files and functions that matter first, then connect them to the observed behavior.
    
    ## Memory and continuity
    
    - Memory and old sessions provide context, not current-state evidence.
    - Read relevant AgentMemory records before relying on historical decisions. Verify dated operational claims against current files or runtime state.
    - Do not write memory records unless the user asks or an approved workflow requires them.
    - Keep Pi memory and session data separate from OMP history.
    
    ## Herdr
    
    - Use Herdr only when the user asks to inspect or control it.
    - Before controlling Herdr, verify `HERDR_ENV=1` and read the installed CLI help.
    - Do not close or restart sessions that the user did not create for this task.
    
    ## Notion workspace
    
    When working with the user's projects, tasks, notes or
    persistent knowledge, first read:
    
    https://app.notion.com/p/3f84b6f58b3b8154a46ddd4bb6605958
    
    Use the existing Notion databases defined there.
    
    - Search before creating anything.
    - Prefer updating an existing record.
    - Do not save every conversation automatically.
    - Keep code and raw execution logs in their original sources.
    - Never delete, merge, or move records without approval.
    - Read the relevant project, task, and accepted decision before substantial work. Fetch them again after compaction before you rely on memory.
    - Keep one authoritative URL per task. If that record is gone, stop writes and ask for the current URL. Do not recreate it.
    - Save a verified milestone to the existing record. Do not wait for session shutdown.
    - Only the assigned owner changes shared task state.
    - Verify each Notion write with a fresh fetch before reporting completion.
    - Do not mark a task Bitti without a verified result. Do not invent a Bitiş date.
    
    If Notion MCP is unavailable, report the limitation and keep the pending update in the session. Do not claim that it was saved.
    

Skills179

  • agent-memory

    Consult Semih's AgentMemory vault on demand when explicit historical context, past architectural decisions, earlier experiment rationale, or cross-project state is needed. Do not use for normal coding tasks.

    • SKILL.md (2.7 KB)
      ---
      name: agent-memory
      description: Consult Semih's AgentMemory vault on demand when explicit historical context, past architectural decisions, earlier experiment rationale, or cross-project state is needed. Do not use for normal coding tasks.
      ---
      
      # AgentMemory On-Demand Consultation Skill
      
      This skill defines the cheapest explicit retrieval model for querying the personal knowledge vault at `/home/semihmutlu/AgentMemory`.
      
      ## When to Use (Trigger)
      - **Activate ONLY when:**
        - The user explicitly asks for historical background, past architectural decisions, or prior experiment rationale.
        - Cross-project patterns or documented personal workflow conventions are explicitly needed to unblock a decision.
      - **DO NOT activate for:**
        - Standard coding, debugging, refactoring, or testing tasks.
        - Determining the current state of a repo (inspect the active repo instead).
      
      ## Core Precedence & Safety Boundaries
      1. **Verified Repo/Runtime State Beats Memory:**
         - Active disk files, git commits, running processes, and test results in the current repository are the single source of truth.
         - AgentMemory may explain *why* an earlier choice was considered, but never dictates *what is current*.
      2. **Task Queues Are Defunct:**
         - `projects/wayfinder.md` was liquidated on 2026-09-07 (`decisions/2026-09-07-wayfinder-tasfiye-ve-yeniden-yon.md`).
         - `pending-actions.md`, `ledger.md`, and `projects/active-pending-work.md` are frozen historical records.
         - Never reopen tasks or generate task queues from AgentMemory.
      3. **Never Inject the Whole Vault:**
         - Retrieve narrowly (1–3 relevant notes maximum). Never read entire directories or load multiple unrelated notes into context.
      
      ## Narrow Retrieval Workflow
      
      ### Step 1: Lexical / Semantic Search with QMD
      Use the local `qmd` tool to find exact matching notes:
      
      ```bash
      # Fast keyword / BM25 search (returns top 5 matching files):
      qmd search "<keywords>" -c agentmemory --format files -n 5
      ```
      
      For nuanced questions, use a structured query:
      ```bash
      qmd query $'intent: <what to find, what to avoid>\nlex: <exact keywords>\nvec: <semantic description>' -c agentmemory --no-rerank --format files -n 5
      ```
      
      ### Step 2: Read Only the Target Note
      Once the specific note path is identified:
      - View the file using `view_file` on `/home/semihmutlu/AgentMemory/<relative-path>` (or run `qmd get "qmd://agentmemory/<relative-path>"`).
      - Target files in `decisions/` (approved decisions) and `learning/` (reusable technical lessons) first.
      - Treat `sessions/` and `archive/` strictly as historical context, not active policies.
      
      ### Step 3: Present Findings Concisely
      - Cite the file path and date of the decision/learning.
      - Summarize only the specific rationale relevant to the user's inquiry.
      
  • agents-sdk

    Build, debug, or review Cloudflare Agents SDK applications using the agents package.

    • SKILL.md (12 KB)
      ---
      name: agents-sdk
      description: Build, debug, or review Cloudflare Agents SDK applications using the agents package.
      ---
      
      # Cloudflare Agents SDK
      
      Your knowledge of the Agents SDK may be outdated. **Prefer retrieval over pre-training** for any Agents SDK task.
      
      ## Retrieval Sources
      
      Cloudflare docs: https://developers.cloudflare.com/agents/index.md
      
      | Topic | Docs URL | Use for |
      |-------|----------|---------|
      | Getting started | [Quick start](https://developers.cloudflare.com/agents/getting-started/quick-start/index.md) | First agent, project setup |
      | Adding to existing project | [Add to existing project](https://developers.cloudflare.com/agents/getting-started/add-to-existing-project/index.md) | Install into existing Workers app |
      | Configuration | [Configuration](https://developers.cloudflare.com/agents/runtime/operations/configuration/index.md) | `wrangler.jsonc`, bindings, assets, deployment |
      | Agent class | [Agents API](https://developers.cloudflare.com/agents/runtime/agents-api/index.md) | Agent lifecycle, patterns, pitfalls |
      | State | [Store and sync state](https://developers.cloudflare.com/agents/runtime/lifecycle/state/index.md) | `setState`, `validateStateChange`, persistence |
      | Routing | [Routing](https://developers.cloudflare.com/agents/runtime/communication/routing/index.md) | URL patterns, `routeAgentRequest` |
      | Callable methods | [Callable methods](https://developers.cloudflare.com/agents/runtime/lifecycle/callable-methods/index.md) | `@callable`, RPC, streaming, timeouts |
      | Scheduling | [Schedule tasks](https://developers.cloudflare.com/agents/runtime/execution/schedule-tasks/index.md) | `schedule()`, `scheduleEvery()`, cron |
      | Workflows | [Run workflows](https://developers.cloudflare.com/agents/runtime/execution/run-workflows/index.md) | `AgentWorkflow`, durable multi-step tasks |
      | HTTP/WebSockets | [WebSockets](https://developers.cloudflare.com/agents/runtime/communication/websockets/index.md) | Lifecycle hooks, hibernation |
      | Chat agents | [Chat agents](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/index.md) | `AIChatAgent`, streaming, tools, persistence |
      | Client SDK | [Client SDK](https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/index.md) | `useAgent`, `AgentClient`, state, RPC, HTTP |
      | Client tools | [Client tools](https://developers.cloudflare.com/agents/harnesses/think/client-tools/index.md) | Client-side tools, `autoContinueAfterToolResult` |
      | Server-driven messages | [Autonomous responses](https://developers.cloudflare.com/agents/communication-channels/chat/autonomous-responses/index.md) | `saveMessages`, `waitUntilStable`, server-initiated turns |
      | Resumable streaming | [Chat agents](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/index.md#resumable-streaming) | Stream recovery on disconnect |
      | Email | [Email](https://developers.cloudflare.com/agents/communication-channels/email/index.md) | Email routing, secure reply resolver |
      | MCP client | [MCP client](https://developers.cloudflare.com/agents/model-context-protocol/apis/client-api/index.md) | Connecting to MCP servers |
      | MCP server | [MCP server](https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/index.md) | Building MCP servers with `createMcpHandler` |
      | MCP transports | [MCP transports](https://developers.cloudflare.com/agents/model-context-protocol/protocol/transport/index.md) | Streamable HTTP, SSE, RPC transport options |
      | Securing MCP servers | [Securing MCP](https://developers.cloudflare.com/agents/model-context-protocol/guides/securing-mcp-server/index.md) | OAuth, proxy MCP, hardening |
      | Human-in-the-loop | [Human-in-the-loop](https://developers.cloudflare.com/agents/concepts/agentic-patterns/human-in-the-loop/index.md) | Workflow approvals, elicitation, timeout handling |
      | Durable execution | [Durable execution](https://developers.cloudflare.com/agents/runtime/execution/durable-execution/index.md) | `runFiber()`, `stash()`, surviving DO eviction |
      | Queue | [Queue](https://developers.cloudflare.com/agents/runtime/execution/queue-tasks/index.md) | Built-in FIFO queue, `queue()` |
      | Retries | [Retries](https://developers.cloudflare.com/agents/runtime/execution/retries/index.md) | `this.retry()`, backoff/jitter |
      | Observability | [Observability](https://developers.cloudflare.com/agents/runtime/operations/observability/index.md) | Diagnostics-channel events |
      | Push notifications | [Push notifications](https://developers.cloudflare.com/agents/communication-channels/webhooks/push-notifications/index.md) | Web Push + VAPID from agents |
      | Webhooks | [Webhooks](https://developers.cloudflare.com/agents/communication-channels/webhooks/index.md) | Receiving external webhooks |
      | Cross-domain auth | [Cross-domain auth](https://developers.cloudflare.com/agents/runtime/operations/cross-domain-authentication/index.md) | WebSocket auth, tokens, CORS |
      | Readonly connections | [Readonly](https://developers.cloudflare.com/agents/runtime/communication/readonly-connections/index.md) | `shouldConnectionBeReadonly` |
      | Voice | [Voice](https://developers.cloudflare.com/agents/communication-channels/voice/index.md) | Experimental STT/TTS, `withVoice` |
      | Browse the web | [Browser tools](https://developers.cloudflare.com/agents/tools/browser/index.md) | Experimental CDP browser automation |
      | Think | [Think](https://developers.cloudflare.com/agents/harnesses/think/index.md) | Experimental higher-level chat agent class |
      | Migrations | [AI SDK v5](https://github.com/cloudflare/agents/blob/main/docs/agents/migration-to-ai-sdk-v5.md), [AI SDK v6](https://github.com/cloudflare/agents/blob/main/docs/agents/migration-to-ai-sdk-v6.md) | Upgrading `@cloudflare/ai-chat` |
      
      ## Capabilities
      
      The Agents SDK provides:
      
      - **Persistent state** — SQLite-backed, auto-synced to clients via `setState`
      - **Callable RPC** — `@callable()` methods invoked over WebSocket
      - **Scheduling** — One-time, recurring (`scheduleEvery`), and cron tasks
      - **Workflows** — Durable multi-step background processing via `AgentWorkflow`
      - **Durable execution** — `runFiber()` / `stash()` for work that survives DO eviction
      - **Queue** — Built-in FIFO queue with retries via `queue()`
      - **Retries** — `this.retry()` with exponential backoff and jitter
      - **MCP integration** — Connect to MCP servers or build your own with `createMcpHandler`
      - **Email handling** — Receive and reply to emails with secure routing
      - **Streaming chat** — `AIChatAgent` with resumable streams, message persistence, tools
      - **Server-driven messages** — `saveMessages`, `waitUntilStable` for proactive agent turns
      - **React hooks** — `useAgent`, `useAgentChat` for client apps
      - **Observability** — `diagnostics_channel` events for state, RPC, schedule, lifecycle
      - **Push notifications** — Web Push + VAPID delivery from agents
      - **Webhooks** — Receive and verify external webhooks
      - **Voice** (experimental) — STT/TTS via `@cloudflare/voice`
      - **Browser tools** (experimental) — CDP-powered browsing via `agents/browser`
      - **Think** (experimental) — Higher-level chat agent via `@cloudflare/think`
      
      ## FIRST: Verify Installation
      
      ```bash
      npm ls agents  # Should show agents package
      ```
      
      If not installed:
      ```bash
      npm install agents
      ```
      
      For chat agents:
      ```bash
      npm install agents @cloudflare/ai-chat ai @ai-sdk/react
      ```
      
      ## Wrangler Configuration
      
      ```jsonc
      {
        "compatibility_flags": ["nodejs_compat"],
        "durable_objects": {
          "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
        },
        "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
      }
      ```
      
      **Gotchas:**
      - Do NOT enable `experimentalDecorators` in tsconfig (breaks `@callable`)
      - Never edit old migrations — always add new tags
      - Each agent class needs its own DO binding + migration entry
      - Add `"ai": { "binding": "AI" }` for Workers AI
      
      ## Agent Class
      
      ```typescript
      import { Agent, routeAgentRequest, callable } from "agents";
      
      type State = { count: number };
      
      export class Counter extends Agent<Env, State> {
        initialState = { count: 0 };
      
        validateStateChange(nextState: State, source: Connection | "server") {
          if (nextState.count < 0) throw new Error("Count cannot be negative");
        }
      
        onStateUpdate(state: State, source: Connection | "server") {
          console.log("State updated:", state);
        }
      
        @callable()
        increment() {
          this.setState({ count: this.state.count + 1 });
          return this.state.count;
        }
      }
      
      export default {
        fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 })
      };
      ```
      
      ## Routing
      
      Requests route to `/agents/{agent-name}/{instance-name}`:
      
      | Class | URL |
      |-------|-----|
      | `Counter` | `/agents/counter/user-123` |
      | `ChatRoom` | `/agents/chat-room/lobby` |
      
      Client: `useAgent({ agent: "Counter", name: "user-123" })`
      
      Custom routing: use `getAgentByName(env.MyAgent, "instance-id")` then `agent.fetch(request)`.
      
      ## Core APIs
      
      | Task | API |
      |------|-----|
      | Read state | `this.state.count` |
      | Write state | `this.setState({ count: 1 })` |
      | SQL query | `` this.sql`SELECT * FROM users WHERE id = ${id}` `` |
      | Schedule (delay) | `await this.schedule(60, "task", payload)` |
      | Schedule (cron) | `await this.schedule("0 * * * *", "task", payload)` |
      | Schedule (interval) | `await this.scheduleEvery(30, "poll")` |
      | RPC method | `@callable() myMethod() { ... }` |
      | Streaming RPC | `@callable({ streaming: true }) stream(res) { ... }` |
      | Start workflow | `await this.runWorkflow("ProcessingWorkflow", params)` |
      | Durable fiber | `await this.runFiber("name", async (ctx) => { ... })` |
      | Enqueue work | `this.queue("handler", payload)` |
      | Retry with backoff | `await this.retry(fn, { maxAttempts: 5 })` |
      | Broadcast to clients | `this.broadcast(message)` |
      | Get connections | `this.getConnections(tag?)` |
      
      ## React Client
      
      Read [client-sdk.md](references/client-sdk.md) for client selection and current connection examples. For chat UI and tools, also read [streaming-chat.md](references/streaming-chat.md).
      
      ## References
      
      ### Core
      - **[references/state-scheduling.md](references/state-scheduling.md)** — State persistence, scheduling, SQL
      - **[references/callable.md](references/callable.md)** — RPC methods, streaming, timeouts
      - **[references/routing.md](references/routing.md)** — URL patterns, custom routing, `getAgentByName`
      - **[references/configuration.md](references/configuration.md)** — Wrangler config, bindings, Vite setup
      
      ### Chat & Streaming
      - **[references/streaming-chat.md](references/streaming-chat.md)** — AIChatAgent, resumable streams, tools
      - **[references/client-sdk.md](references/client-sdk.md)** — `useAgent`, `useAgentChat`, `AgentClient`
      - **[references/server-driven-messages.md](references/server-driven-messages.md)** — Trigger patterns, `saveMessages`
      - **[references/human-in-the-loop.md](references/human-in-the-loop.md)** — Approval flows, `needsApproval`
      
      ### Background Processing
      - **[references/workflows.md](references/workflows.md)** — Durable Workflows integration
      - **[references/durable-execution.md](references/durable-execution.md)** — `runFiber`, `stash`, surviving eviction
      - **[references/queue-retries.md](references/queue-retries.md)** — Built-in queue, retry with backoff
      
      ### Integrations
      - **[references/mcp.md](references/mcp.md)** — MCP client and server, transports, securing
      - **[references/email.md](references/email.md)** — Email routing and handling
      - **[references/webhooks-push.md](references/webhooks-push.md)** — Webhooks, push notifications
      - **[references/observability.md](references/observability.md)** — Diagnostics-channel events
      
      ### Experimental
      - **[references/think.md](references/think.md)** — `@cloudflare/think` higher-level chat agent
      - **[references/voice.md](references/voice.md)** — `@cloudflare/voice` STT/TTS
      - **[references/codemode.md](references/codemode.md)** — Code Mode for tool orchestration
      - **[references/browse-the-web.md](references/browse-the-web.md)** — CDP browser tools
      
    • references/browse-the-web.md (1.6 KB)
      # Browse the Web (Experimental)
      
      Fetch https://developers.cloudflare.com/agents/tools/browser/index.md for complete documentation.
      
      CDP-powered browser tools that let agents scrape, screenshot, and interact with web pages.
      
      ## Setup
      
      ```jsonc
      // wrangler.jsonc
      {
        "browser": { "binding": "BROWSER" },
        "worker_loaders": [{ "binding": "LOADER" }],
        "compatibility_flags": ["nodejs_compat"]
      }
      ```
      
      ## Usage with AI SDK
      
      ```typescript
      import { createBrowserTools } from "agents/browser/ai";
      
      export class MyAgent extends AIChatAgent<Env> {
        async onChatMessage(onFinish) {
          const browserTools = createBrowserTools({
            browser: this.env.BROWSER,
            loader: this.env.LOADER
          });
      
          const result = streamText({
            model: openai("gpt-4o"),
            messages: await convertToModelMessages(this.messages),
            tools: { ...myTools, ...browserTools },
            onFinish
          });
          return result.toUIMessageStreamResponse();
        }
      }
      ```
      
      ## Available Tools
      
      | Tool | Purpose |
      |------|---------|
      | `browser_search` | Search the web and return results |
      | `browser_execute` | Navigate to URL, execute JS, return results |
      
      The LLM writes async JavaScript IIFEs that run in a fresh browser session.
      
      ## When to Use
      
      - Need a real browser (JS rendering, screenshots, interaction) → browser tools
      - Just need HTML/API data → use `fetch()` instead (faster, cheaper)
      
      ## Low-Level API
      
      ```typescript
      import { connectBrowser, CdpSession } from "agents/browser";
      
      const browser = await connectBrowser(this.env.BROWSER);
      const cdp = new CdpSession(browser);
      await cdp.send("Page.navigate", { url: "https://example.com" });
      ```
      
    • references/callable.md (2.1 KB)
      # Callable Methods
      
      Fetch https://developers.cloudflare.com/agents/runtime/lifecycle/callable-methods/index.md for complete documentation.
      
      ## Overview
      
      `@callable()` exposes agent methods to clients via WebSocket RPC.
      
      ```typescript
      import { Agent, callable } from "agents";
      
      export class MyAgent extends Agent<Env, State> {
        @callable()
        async greet(name: string): Promise<string> {
          return `Hello, ${name}!`;
        }
      
        @callable()
        async processData(data: unknown): Promise<Result> {
          // Long-running work
          return result;
        }
      }
      ```
      
      ## Client Usage
      
      ```typescript
      // Basic call
      const greeting = await agent.call("greet", ["World"]);
      
      // With timeout
      const result = await agent.call("processData", [data], {
        timeout: 5000  // 5 second timeout
      });
      ```
      
      ## Streaming Responses
      
      ```typescript
      import { Agent, callable, StreamingResponse } from "agents";
      
      export class MyAgent extends Agent<Env, State> {
        @callable({ streaming: true })
        async streamResults(stream: StreamingResponse, query: string) {
          for await (const item of fetchResults(query)) {
            stream.send(JSON.stringify(item));
          }
          stream.close();
        }
      
        @callable({ streaming: true })
        async streamWithError(stream: StreamingResponse) {
          try {
            // ... work
          } catch (error) {
            stream.error(error.message);  // Signal error to client
            return;
          }
          stream.close();
        }
      }
      ```
      
      Client with streaming:
      
      ```typescript
      await agent.call("streamResults", ["search term"], {
        stream: {
          onChunk: (data) => console.log("Chunk:", data),
          onDone: () => console.log("Complete"),
          onError: (error) => console.error("Error:", error)
        }
      });
      ```
      
      ## Introspection
      
      ```typescript
      // Get list of callable methods on an agent
      const methods = await agent.call("getCallableMethods", []);
      // Returns: ["greet", "processData", "streamResults", ...]
      ```
      
      ## When to Use
      
      | Scenario | Use |
      |----------|-----|
      | Browser/mobile calling agent | `@callable()` |
      | External service calling agent | `@callable()` |
      | Worker calling agent (same codebase) | DO RPC directly |
      | Agent calling another agent | `getAgentByName()` + DO RPC |
      
    • references/client-sdk.md (1.2 KB)
      # Client SDK
      
      Choose `useAgent` for React state/RPC, `AgentClient` for other WebSocket clients, and `agentFetch` for one-off HTTP requests. Add `useAgentChat` when the UI needs chat messages and streaming. Check installed package versions before adapting current examples.
      
      | Task | Documentation |
      |------|---------------|
      | Connect, sync state, call RPC, or send HTTP requests | [Client SDK](https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/index.md) — hooks, vanilla JS, typed calls, streaming callbacks, and connection options |
      | Build chat UI | [Chat agents](https://developers.cloudflare.com/agents/communication-channels/chat/chat-agents/index.md) — `useAgentChat`, message rendering, status, and tool interactions |
      | Authenticate across origins | [Cross-domain authentication](https://developers.cloudflare.com/agents/runtime/operations/cross-domain-authentication/index.md) — token validation and WebSocket authentication |
      
      Keep client instance selection consistent with server routing. For authentication, account for token refresh on reconnect and query caching. Close manually created `AgentClient` connections when finished; React hooks manage their own cleanup.
      
    • references/codemode.md (2.8 KB)
      # Codemode (Experimental)
      
      Fetch https://developers.cloudflare.com/agents/tools/codemode/api-reference/index.md for complete documentation.
      
      Codemode lets LLMs write and execute code that orchestrates your tools, instead of calling them one at a time. The LLM gets a single "write code" tool; generated JavaScript runs in an isolated Worker sandbox.
      
      ## When to Use
      
      | Scenario | Use Codemode? |
      |----------|---------------|
      | Single tool call | No — standard tool calling is simpler |
      | Chained tool calls with logic | Yes |
      | Conditional logic across tools | Yes |
      | MCP multi-server workflows | Yes |
      | Simple Q&A chat | No |
      
      ## Setup
      
      ### Wrangler Config
      
      ```jsonc
      {
        "worker_loaders": [{ "binding": "LOADER" }],
        "compatibility_flags": ["nodejs_compat"]
      }
      ```
      
      ### Install
      
      ```bash
      npm install @cloudflare/codemode ai zod
      ```
      
      ## Usage
      
      ```typescript
      import { createCodeTool } from "@cloudflare/codemode/ai";
      import { DynamicWorkerExecutor } from "@cloudflare/codemode";
      import { streamText, tool, convertToModelMessages } from "ai";
      import { z } from "zod";
      
      const tools = {
        getWeather: tool({
          description: "Get weather for a location",
          inputSchema: z.object({ location: z.string() }),
          execute: async ({ location }) => `Weather: ${location} 72°F`
        }),
        sendEmail: tool({
          description: "Send an email",
          inputSchema: z.object({ to: z.string(), subject: z.string(), body: z.string() }),
          execute: async ({ to, subject, body }) => `Email sent to ${to}`
        })
      };
      
      export class MyAgent extends Agent<Env, State> {
        async onChatMessage() {
          const executor = new DynamicWorkerExecutor({
            loader: this.env.LOADER
          });
      
          const codemode = createCodeTool({ tools, executor });
      
          const result = streamText({
            model,
            system: "You are a helpful assistant.",
            messages: await convertToModelMessages(this.messages),
            tools: { codemode }
          });
      
          return result.toUIMessageStreamResponse();
        }
      }
      ```
      
      ## With MCP Tools
      
      ```typescript
      const codemode = createCodeTool({
        tools: {
          ...myTools,
          ...this.mcp.getAITools()
        },
        executor
      });
      ```
      
      ## How It Works
      
      1. `createCodeTool` generates TypeScript type definitions from your tools
      2. The LLM writes an async arrow function calling `codemode.toolName(args)`
      3. Code runs in an isolated Worker sandbox via `DynamicWorkerExecutor`
      4. Tool calls route back to the host via Workers RPC
      5. External `fetch()` is blocked by default — sandbox can only call your tools
      
      ## Network Isolation
      
      ```typescript
      const executor = new DynamicWorkerExecutor({
        loader: env.LOADER,
        globalOutbound: null           // default — fully isolated
        // globalOutbound: env.MY_SERVICE  // route through a Fetcher
      });
      ```
      
      ## Limitations
      
      - Experimental — API may change
      - `needsApproval` tools execute immediately in sandbox (no approval pause yet)
      - JavaScript execution only
      - Requires `worker_loaders` binding
      
  • analyze-sessions

    Analyze past omp and pi agent sessions stored under ~/.omp/agent/sessions and ~/.pi/agent/sessions. Use when the user asks about cost (totals, per project, per model, per day), wants to mine prompting patterns from past prompts, view a specific past session, or search across session transcripts.

    • .gitignore (21 B)
      {__pycache__/,*.pyc}
      
    • SKILL.md (6.3 KB)
      ---
      name: analyze-sessions
      description: Analyze past omp and pi agent sessions stored under ~/.omp/agent/sessions and ~/.pi/agent/sessions. Use when the user asks about cost (totals, per project, per model, per day), wants to mine prompting patterns from past prompts, view a specific past session, or search across session transcripts.
      ---
      
      # Analyze Sessions
      
      Tools for querying past omp and pi sessions. All scripts are stdlib Python 3, no dependencies, and read `~/.omp/agent/sessions/` and `~/.pi/agent/sessions/`.
      
      ## Data shape (one-liner)
      
      Each session is a JSONL file. Records are `session` (header with `cwd`, `id`, `timestamp`), `model_change`, `thinking_level_change`, and `message` (roles: `user`, `assistant`, `toolResult`). Assistant messages carry `usage.cost` already split into input/output/cacheRead/cacheWrite/total — cost analysis is just summing those. Subagent transcripts live nested inside the parent session's directory.
      
      ## Scripts
      
      All scripts share the same filter vocabulary (see "Shared filters" below). Run them with `python3` from anywhere:
      
      ```bash
      python3 ~/.agents/skills/analyze-sessions/scripts/<script>.py [args]
      ```
      
      ### `cost.py` — cost rollups
      
      Subagent costs are **included by default** so totals reflect actual spend. Pass `--show-subagents` to see the subagent share per row, or `--no-subagents` to exclude.
      
      ```bash
      # Last 7 days, broken down by day (default)
      python3 cost.py
      
      # Last 30 days, top 10 projects by spend
      python3 cost.py --since 30d --by project --limit 10
      
      # Cost-per-model (each assistant message credited to its own model)
      python3 cost.py --since 30d --by model
      
      # The 10 most expensive sessions of the last month
      python3 cost.py --since 30d --by session --limit 10
      
      # Cost of one project, all time
      python3 cost.py --cwd /path/to/your/project
      
      # Grand total only
      python3 cost.py --since 30d --by total
      
      # Machine-readable
      python3 cost.py --since 30d --by day --json
      ```
      
      Groupings: `total`, `day`, `project`, `model`, `session`. When grouping, `--limit` caps groups, not sessions.
      
      ### `prompts.py` — dump user prompts for pattern mining
      
      Output is markdown grouped by project (`--format jsonl` available). Prompts above `--max-chars` are dropped because they're almost always pasted context, not actual prompting.
      
      ```bash
      # Default: markdown dump, max 2000 chars per prompt
      python3 prompts.py --since 30d
      
      # Tighter cap, one prompt per JSONL line
      python3 prompts.py --since 7d --max-chars 1500 --format jsonl
      
      # One project's prompts
      python3 prompts.py --cwd /path/to/your/project --since 30d
      
      # Prompts that mention a topic
      python3 prompts.py --grep "rate limit" --since 60d
      ```
      
      The typical workflow for "find patterns I could turn into global instructions":
      1. Run `prompts.py --since 30d` and read the output.
      2. Group by recurring themes (same correction repeated across projects, same setup question, same complaint).
      3. Propose additions to global `CLAUDE.md` / project AGENTS.md / pi instructions.
      
      ### `show_session.py` — render one session as markdown
      
      ```bash
      # The most recent session
      python3 show_session.py --latest
      
      # A specific session by id prefix (8 chars is enough)
      python3 show_session.py --session 019e475b
      
      # The most recent session in a project
      python3 show_session.py --latest --cwd /path/to/your/project
      
      # Include subagent transcripts inline below
      python3 show_session.py --session 019e475b --include-subagents-content
      
      # Drop thinking entirely / show fewer chars
      python3 show_session.py --session 019e475b --max-thinking -1 --max-tool-output 800
      ```
      
      Each tool result is fenced with `…[N more chars elided]…` if truncated. Default truncations: tool output 2000, assistant text 4000, thinking 600. Pass `0` to a limit to disable it, `-1` to `--max-thinking` to omit thinking entirely.
      
      ### `search.py` — search across transcripts
      
      Substring by default, regex with `--regex` (smart-case). Searches both user and assistant text by default.
      
      ```bash
      # Substring across everything
      python3 search.py "supabase RLS"
      
      # Only my prompts, last 60 days
      python3 search.py "global instruction" --in user --since 60d
      
      # Regex
      python3 search.py --regex "TODO\\(.+\\)"
      
      # More context per match
      python3 search.py "rate limit" --context 2
      ```
      
      Each hit prints the session header plus a `python3 show_session.py --session <id>` line so you can drill in directly.
      
      ## Shared filters
      
      Available on **all four scripts**:
      
      | Flag | Meaning |
      |---|---|
      | `--since WHEN` / `--until WHEN` | `YYYY-MM-DD`, ISO datetime, or relative: `7d`, `2w`, `3h`, `30m` |
      | `--cwd SUBSTR` | Substring match on the session's real `cwd`. Repeatable. |
      | `--model SUBSTR` | Substring match on model id. Repeatable. |
      | `--provider {anthropic,openai,google}` | |
      | `--session ID` | Session id or prefix (8 chars usually unique) |
      | `--include-subagents` / `--no-subagents` | Override the script default |
      | `--limit N` | Cap items returned (caps groups, not sessions, for `cost.py` group views) |
      | `--min-cost USD` | Drop sessions below this spend |
      | `--min-messages N` | Drop short sessions |
      | `--errors-only` | Only sessions with at least one `toolResult.isError` |
      | `--grep SUBSTR` | Case-insensitive substring on the session's concatenated user prompts |
      
      ### Subagent defaults
      - `cost.py`: **included** (totals = real spend)
      - `prompts.py`, `show_session.py`, `search.py`: **excluded** (a subagent's "user" message is a task description written by another agent, not your prompt)
      
      ## Common queries
      
      | Question | Command |
      |---|---|
      | Total cost in the last 7 days | `python3 cost.py --since 7d --by total` |
      | Daily spend trend, last 30 days | `python3 cost.py --since 30d --by day` |
      | Most expensive projects this month | `python3 cost.py --since 30d --by project --limit 10` |
      | Most expensive sessions ever | `python3 cost.py --by session --limit 10 --until 1d` |
      | Cost of one project | `python3 cost.py --cwd /path/to/proj` |
      | Patterns in my prompting | `python3 prompts.py --since 30d --max-chars 1500` → read the output |
      | What did I do yesterday | `python3 show_session.py --latest --since 1d` |
      | Where did the agent struggle | `python3 cost.py --since 30d --errors-only --by session --limit 10` |
      | Find old session about X | `python3 search.py "X"` |
      
      ## Notes
      
      - All paths are read-only; the scripts never modify session files.
      - The library (`scripts/sessions.py`) is reusable: import it for ad-hoc analysis.
      - A full scan over a few hundred sessions takes ~1–2 seconds. No caching.
      
    • scripts/__pycache__/sessions.cpython-314.pyc (27 KB)
    • scripts/cost.py (7.3 KB)
      #!/usr/bin/env python3
      """Cost rollups across pi sessions.
      
      Examples:
        python3 cost.py                                # last 7d, by day
        python3 cost.py --since 30d --by project
        python3 cost.py --since 30d --by model
        python3 cost.py --cwd /Volumes/T7/code/blanc   # one project, all time
        python3 cost.py --since 30d --by session --limit 10 --show-subagents
      """
      
      from __future__ import annotations
      
      import argparse
      import json
      import sys
      from collections import defaultdict
      from datetime import datetime, timezone
      from pathlib import Path
      
      import sessions as S
      
      
      GROUPINGS = ["total", "day", "project", "model", "session"]
      
      
      def main() -> int:
          p = argparse.ArgumentParser(description="Cost rollups across pi sessions.")
          p.add_argument("--by", choices=GROUPINGS, default="day",
                         help="Grouping for the breakdown table (default: day). "
                              "'total' prints only the grand total.")
          p.add_argument("--show-subagents", action="store_true",
                         help="Also print a row with the subagent share for each group.")
          p.add_argument("--json", action="store_true", help="Emit JSON instead of a table.")
          # Subagents are INCLUDED by default for cost so the totals reflect real spend.
          S.add_filter_args(p, subagents_default=True)
          args = p.parse_args()
      
          # Default to last 7 days if no date filter given.
          if not args.since and not args.until and not args.session:
              args.since = "7d"
      
          filters = S.filters_from_args(args, subagents_default=True)
          # For grouped views, --limit caps groups, not sessions. Drop it from the
          # session-level filter so grouping sees every matching session.
          group_limit = args.limit if args.by != "total" else None
          if args.by != "total":
              filters.limit = None
      
          summaries = S.load_summaries(filters)
      
          if not summaries:
              S.stderr("No sessions matched.")
              return 0
      
          if args.json:
              report = build_report(summaries, args.by)
              print(json.dumps(report, indent=2, default=str))
              return 0
      
          if args.by == "total":
              print_grand_total(summaries)
              return 0
      
          print_grand_total(summaries)
          print()
          print_grouped(summaries, args.by, show_subagents=args.show_subagents,
                        limit=group_limit)
          return 0
      
      
      # ---------------------------------------------------------------------------
      # Grouping
      # ---------------------------------------------------------------------------
      
      
      def session_keys(s: S.SessionSummary, by: str):
          """Return the group key(s) a session contributes to, and a per-key cost
          override. For 'model' a session can split across multiple keys, and we
          re-scan the file to credit per-message cost. For everything else it's a
          single key with full session cost."""
          if by == "day":
              k = (s.started_at.astimezone().strftime("%Y-%m-%d")
                   if s.started_at else "unknown")
              yield k, s.cost_total
          elif by == "project":
              yield (s.cwd or "?"), s.cost_total
          elif by == "session":
              yield s.id, s.cost_total
          elif by == "model":
              # Walk assistant messages to credit each one's cost to its model.
              per_model = defaultdict(float)
              for rec in S.iter_records(s.path):
                  if rec.get("type") != "message":
                      continue
                  m = rec.get("message") or {}
                  if m.get("role") != "assistant":
                      continue
                  model = m.get("model") or "?"
                  cost = ((m.get("usage") or {}).get("cost") or {}).get("total") or 0
                  per_model[model] += float(cost)
              if not per_model and s.models:
                  # Fall back to splitting evenly across the session's models.
                  share = s.cost_total / len(s.models)
                  for mdl in s.models:
                      per_model[mdl] = share
              for k, v in per_model.items():
                  yield k, v
          else:
              yield "all", s.cost_total
      
      
      def build_report(summaries, by: str) -> dict:
          rows = defaultdict(lambda: dict(cost=0.0, sessions=0, messages=0, errors=0,
                                          sub_cost=0.0, sub_sessions=0))
          for s in summaries:
              for k, cost in session_keys(s, by):
                  r = rows[k]
                  r["cost"] += cost
                  r["sessions"] += 1
                  r["messages"] += s.message_count
                  r["errors"] += s.error_count
                  if s.is_subagent:
                      r["sub_cost"] += cost
                      r["sub_sessions"] += 1
          return {
              "grouping": by,
              "total_cost": sum(s.cost_total for s in summaries),
              "total_sessions": len(summaries),
              "groups": dict(rows),
          }
      
      
      # ---------------------------------------------------------------------------
      # Printing
      # ---------------------------------------------------------------------------
      
      
      def print_grand_total(summaries) -> None:
          total = sum(s.cost_total for s in summaries)
          top_level = [s for s in summaries if not s.is_subagent]
          sub = [s for s in summaries if s.is_subagent]
          tok_in = sum(s.tok_input for s in summaries)
          tok_out = sum(s.tok_output for s in summaries)
          cache_r = sum(s.cost_cache_read for s in summaries)
          cache_w = sum(s.cost_cache_write for s in summaries)
      
          print(f"Total cost:  {S.fmt_money(total)}")
          print(f"  sessions:  {len(top_level)} top-level"
                + (f"  +  {len(sub)} subagent" if sub else ""))
          print(f"  cache:     read {S.fmt_money(cache_r)}   write {S.fmt_money(cache_w)}")
          print(f"  tokens:    in {tok_in:,}   out {tok_out:,}")
          if summaries:
              first = min((s.started_at for s in summaries if s.started_at), default=None)
              last = max((s.started_at for s in summaries if s.started_at), default=None)
              if first and last:
                  print(f"  window:    {S.fmt_short_ts(first)}  →  {S.fmt_short_ts(last)}")
      
      
      def print_grouped(summaries, by: str, *, show_subagents: bool, limit) -> None:
          report = build_report(summaries, by)
          groups = report["groups"]
      
          # Sort: day asc (chronological), session desc by cost, others desc by cost
          items = list(groups.items())
          if by == "day":
              items.sort(key=lambda kv: kv[0])
          else:
              items.sort(key=lambda kv: kv[1]["cost"], reverse=True)
      
          if limit and by != "day":
              items = items[:limit]
      
          label = {"day": "DATE", "project": "PROJECT", "model": "MODEL",
                   "session": "SESSION"}[by]
          # Compute column widths
          keycol = max(len(label), max((len(_render_key(k, by)) for k, _ in items), default=4))
          keycol = min(keycol, 70)
      
          headers = [label.ljust(keycol), "COST".rjust(10), "SESS".rjust(5),
                     "MSGS".rjust(6), "ERR".rjust(5)]
          if show_subagents:
              headers.append("SUB$".rjust(9))
          print("  ".join(headers))
          print("  ".join("-" * len(h) for h in headers))
      
          for k, r in items:
              key_disp = _render_key(k, by)
              if len(key_disp) > keycol:
                  key_disp = "…" + key_disp[-(keycol - 1):]
              row = [
                  key_disp.ljust(keycol),
                  S.fmt_money(r["cost"]).rjust(10),
                  str(r["sessions"]).rjust(5),
                  str(r["messages"]).rjust(6),
                  str(r["errors"]).rjust(5),
              ]
              if show_subagents:
                  row.append(S.fmt_money(r["sub_cost"]).rjust(9))
              print("  ".join(row))
      
      
      def _render_key(k: str, by: str) -> str:
          if by == "session":
              return k[:8] if k else "?"
          return k or "?"
      
      
      if __name__ == "__main__":
          sys.exit(main())
      
    • scripts/prompts.py (4.8 KB)
      #!/usr/bin/env python3
      """Dump user prompts across pi sessions for pattern analysis.
      
      By default returns markdown grouped by project (cwd), newest first, with one
      section per session containing each user prompt in that session.
      
      Prompts longer than --max-chars are dropped (they're almost always pasted
      context, not actual prompting), so the output is suitable for handing to a
      model that's looking for prompting patterns.
      
      Examples:
        python3 prompts.py --since 30d
        python3 prompts.py --since 7d --max-chars 1500 --format jsonl
        python3 prompts.py --cwd /Volumes/T7/code/blanc --since 30d
        python3 prompts.py --grep "global instruction"
      """
      
      from __future__ import annotations
      
      import argparse
      import json
      import sys
      from collections import defaultdict
      
      import sessions as S
      
      
      def main() -> int:
          p = argparse.ArgumentParser(description="Dump user prompts for pattern analysis.")
          p.add_argument("--format", choices=["md", "jsonl"], default="md",
                         help="Output format (default: md).")
          p.add_argument("--max-chars", type=int, default=2000,
                         help="Drop prompts longer than this (default: 2000). 0 = no limit.")
          p.add_argument("--min-chars", type=int, default=1,
                         help="Drop prompts shorter than this (default: 1).")
          # Subagents OFF by default: their "user" messages are agent-authored task
          # descriptions, not your prompts.
          S.add_filter_args(p, subagents_default=False)
          args = p.parse_args()
      
          filters = S.filters_from_args(args, subagents_default=False)
          summaries = S.load_summaries(filters)
      
          # Re-scan each matching session and collect its user prompts.
          sess_prompts = []  # list of (summary, [prompts])
          total_prompts = 0
          for s in summaries:
              prompts = _collect_prompts(s.path, args.max_chars, args.min_chars)
              if not prompts:
                  continue
              sess_prompts.append((s, prompts))
              total_prompts += len(prompts)
      
          if not sess_prompts:
              S.stderr("No prompts matched.")
              return 0
      
          if args.format == "jsonl":
              for s, prompts in sess_prompts:
                  for ts_ms, text in prompts:
                      out = {
                          "session_id": s.id,
                          "cwd": s.cwd,
                          "timestamp": ts_ms,
                          "text": text,
                      }
                      print(json.dumps(out, ensure_ascii=False))
              S.stderr(f"# {total_prompts} prompts across {len(sess_prompts)} sessions")
              return 0
      
          _render_markdown(sess_prompts, total_prompts)
          return 0
      
      
      def _collect_prompts(path, max_chars: int, min_chars: int):
          """Walk the session JSONL and return [(timestamp_ms, text), ...] for user
          messages within the length window."""
          out = []
          for rec in S.iter_records(path):
              if rec.get("type") != "message":
                  continue
              m = rec.get("message") or {}
              if m.get("role") != "user":
                  continue
              text = _extract_text(m.get("content"))
              if not text:
                  continue
              n = len(text)
              if n < min_chars:
                  continue
              if max_chars and n > max_chars:
                  continue
              out.append((m.get("timestamp"), text))
          return out
      
      
      def _extract_text(content) -> str:
          if not isinstance(content, list):
              return ""
          chunks = []
          for c in content:
              if isinstance(c, dict) and c.get("type") == "text":
                  t = c.get("text")
                  if t:
                      chunks.append(t)
          return "\n".join(chunks)
      
      
      def _render_markdown(sess_prompts, total_prompts: int) -> None:
          # Group by project (cwd), newest first within each group, project order by
          # most recent session.
          by_proj = defaultdict(list)
          for s, prompts in sess_prompts:
              by_proj[s.cwd or "?"].append((s, prompts))
      
          proj_order = sorted(by_proj.keys(),
                              key=lambda k: max((s.started_at for s, _ in by_proj[k]
                                                 if s.started_at), default=None) or 0,
                              reverse=True)
      
          print(f"# Pi prompts dump")
          print(f"_{total_prompts} prompts across {len(sess_prompts)} sessions, "
                f"{len(by_proj)} projects._")
          print()
      
          for proj in proj_order:
              print(f"## {proj}")
              print()
              # newest session first
              for s, prompts in sorted(by_proj[proj],
                                       key=lambda x: x[0].started_at or 0,
                                       reverse=True):
                  print(f"### {S.fmt_short_ts(s.started_at)}  ·  `{s.short_id}`  "
                        f"·  {len(prompts)} prompt{'s' if len(prompts) != 1 else ''}")
                  print()
                  for _, text in prompts:
                      # Indent as blockquote to keep prompts visually distinct.
                      for line in text.splitlines() or [""]:
                          print(f"> {line}")
                      print()
      
      
      if __name__ == "__main__":
          sys.exit(main())
      
  • apple-ui

    Apple HIG-inspired UI skill for React/Next.js/Tailwind. NEVER trigger automatically. Use ONLY when user explicitly says "Apple style", "Apple HIG", "Apple UI", or "/apple-ui". Two modes — BUILD (fikir → UI plan + component skeleton) and REVIEW (mevcut UI → S1–S10 smell analysis + score/10). Steve skill handles philosophy (why); this handles execution (how).

    • SKILL.md (2.6 KB)
      ---
      name: apple-ui
      description: Apple HIG-inspired UI skill for React/Next.js/Tailwind. NEVER trigger automatically. Use ONLY when user explicitly says "Apple style", "Apple HIG", "Apple UI", or "/apple-ui". Two modes — BUILD (fikir → UI plan + component skeleton) and REVIEW (mevcut UI → S1–S10 smell analysis + score/10). Steve skill handles philosophy (why); this handles execution (how).
      license: MIT
      ---
      
      # Apple UI Skill
      
      > The interface fades behind the user's task.
      > One primary action. One visual weight. One thing this screen does.
      
      ---
      
      ## Dispatch
      
      Read the user input and pick one mode:
      
      | Input type | Mode |
      |-----------|------|
      | Feature idea, rough description, "build me", "design a" | **BUILD** |
      | Code snippet, screenshot, design description for review | **REVIEW** |
      | Ambiguous | Ask: "Build a new screen or review an existing one?" |
      
      Then follow the mode protocol below.
      
      ---
      
      ## BUILD mode
      
      Load `references/builder.md` and execute it in full.
      
      Short version if references/ is unavailable:
      1. Extract core interaction (what is the primary action?)
      2. Apply defaults: light+dark, 8pt grid, system font, one accent + gray
      3. Output: Overview → Layout diagram → Component tree → Data flow → States → Responsive → Code sketch
      
      Constraints (always apply):
      - One primary CTA per viewport
      - 8pt spacing scale only
      - ≤3 font sizes, ≤2 weights, ≤2 accent colors
      - All touch targets ≥44×44px
      - Every component handles: loading, empty, error, success
      
      ---
      
      ## REVIEW mode
      
      Load `references/reviewer.md` for full protocol and `references/checklist.md` for scoring.
      
      Short version if references/ is unavailable:
      Run S1–S10 smell detector, output top 5 issues with exact fixes, score /10.
      
      **S1–S10 quick reference:**
      - S1 Too Many Visual Weights
      - S2 Weak Hierarchy
      - S3 Fake Premium Aesthetic
      - S4 Low Information Density
      - S5 Unclear Primary Action
      - S6 Component Soup
      - S7 Spacing Inconsistency
      - S8 Decorative Motion
      - S9 Inaccessible Contrast
      - S10 Content Hidden Behind Pretty UI
      
      ---
      
      ## Reference files
      
      Load on demand — only read what the active mode needs:
      
      - `references/builder.md` — full BUILD protocol with output format
      - `references/reviewer.md` — full REVIEW protocol with smell taxonomy
      - `references/skillset.md` — Apple HIG heuristics (principles, layout, interaction, components, a11y)
      - `references/playbook.md` — practical patterns (dashboards, share cards, onboarding, testing tools)
      - `references/checklist.md` — L/H/I/A/C/M checklist for pre-ship review
      
      ---
      
      > Pair with `/steve` for philosophy. This skill handles execution.
      
    • references/builder.md (4.0 KB)
      You are a UI designer specialized in building Apple-inspired web interfaces using React/Next.js and Tailwind CSS.
      
      The user will give you a rough product idea (a sentence, a description, a feature list). Your job is to produce a concrete UI plan.
      
      ## Process
      
      1. **Extract the core interaction** — What is the primary action the user takes? What is the information they need most?
      2. **Assume reasonable defaults** — If the user didn't specify:
         - Dark or light mode → light with dark mode support
         - Breakpoints → 375px / 768px / 1024px / 1440px
         - Spacing → 8‑point grid
         - Font → system font stack (Inter or system-ui)
         - Color → one accent + neutral gray
      3. **Only ask when truly ambiguous** — If the given info is missing a critical constraint (e.g., "this is for mobile only" vs "responsive required"), ask one clear question. Otherwise, proceed.
      4. **Produce the plan.**
      
      ## Output Format
      
      ### Overview
      - What this screen does (1 sentence)
      - Key interaction pattern
      
      ### Layout Structure
      ```
      ┌─────────────────────────────────────────┐
      │  Navigation (title + 1 action)          │
      ├─────────────────────────────────────────┤
      │  Primary content area                    │
      │  ┌───────────┐  ┌───────────────────┐   │
      │  │ Widget A  │  │  Main data view   │   │
      │  │ Metric    │  │  (list/grid/table) │   │
      │  │ Sparkline │  │                    │   │
      │  └───────────┘  └───────────────────┘   │
      ├─────────────────────────────────────────┤
      │  Bottom action bar (mobile)             │
      └─────────────────────────────────────────┘
      ```
      
      ### Component Tree
      ```
      <Page>
        <NavBar title="..." action={<Button />} />
        <Content>
          <MetricCard label="..." value="..." />
          <DataList items={...} />
        </Content>
        <BottomBar>
          <Button variant="primary">CTA</Button>
        </BottomBar>
      </Page>
      ```
      
      ### Data Flow
      - What data is needed
      - Where it comes from (props, fetch, state)
      - Loading / empty / error states for each
      
      ### States to Handle
      | State | What renders |
      |-------|-------------|
      | Loading | Skeleton cards, shimmer |
      | Empty | Illustration + "No items yet" + CTA |
      | Error | Inline error + retry button |
      | Success | Content with subtle entrance animation |
      
      ### Responsive Behavior
      - Mobile (375px): single column, full-width inputs, bottom action bar
      - Tablet (768px): 2‑column grid, side panels
      - Desktop (1280px): multi-column, sidebars, keyboard shortcuts
      
      ### Accessibility Checklist
      - Focus order follows visual layout
      - Color not the only indicator
      - Touch targets ≥ 44×44px
      - Screen reader labels on all interactive elements
      - `prefers-reduced-motion` respected
      
      ### Code Sketch (React/Tailwind)
      ```tsx
      // Key component skeleton — not full implementation, just the structural decisions
      export function MetricCard({ label, value, trend }: MetricCardProps) {
        return (
          <div className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm">
            <p className="text-sm text-gray-500">{label}</p>
            <p className="mt-1 text-2xl font-semibold text-gray-900">{value}</p>
            {trend && <TrendIndicator direction={trend.direction} />}
          </div>
        )
      }
      ```
      
      ## Design Constraints
      - One primary CTA per viewport. No competition.
      - 8‑point spacing scale only.
      - 3 font sizes max, 2 weights max, 2 accent colors max.
      - All interactive elements ≥ 44×44px.
      - No decorative motion. Every animation has a purpose.
      - Content in plain view — no tooltip-only info for critical data.
      - Max 3 onboarding steps. Max 5 tab bar items.
      
      ---
      
      Provide the UI plan now.
      
    • references/checklist.md (4.9 KB)
      # Apple UI Review Checklist
      
      > For each screen, mark Pass / Fail / N/A. A screen passes if all items in the relevant group pass.
      
      ---
      
      ## Layout
      
      | # | Check | How to test |
      |---|-------|-------------|
      | L1 | Content area is ≤1200px wide on desktop | Measure at 1920px viewport |
      | L2 | 8‑point spacing scale is used consistently | Inspect gaps: only 4, 8, 12, 16, 24, 32, 48, 64 |
      | L3 | No content is clipped or overlapped at 375px, 768px, 1280px | Resize browser to each breakpoint |
      | L4 | Touch targets are ≥44×44px with ≥8px between them | Inspect computed size of all buttons, links, inputs |
      | L5 | Safe area insets applied (notch, home indicator) | Test in iOS Safari / Simulator |
      | L6 | Page is scrollable in one direction only | No horizontal scroll at any breakpoint |
      | L7 | Form inputs and buttons are full-width on mobile | Check at 375px width |
      
      ## Visual Hierarchy
      
      | # | Check | How to test |
      |---|-------|-------------|
      | H1 | The page purpose is clear within 3 seconds of looking at it | Cover the title, can you tell the purpose? |
      | H2 | One primary action per viewport | Count filled/high-contrast buttons. Should be ≤1 |
      | H3 | Font hierarchy uses ≤3 sizes, ≤2 weights, ≤2 accent colors | Inspect all text nodes |
      | H4 | The most important element is the most visually dominant | Eyes naturally land on it first |
      | H5 | Secondary info is visually muted (lower weight, smaller, gray) | Compare against primary text |
      | H6 | Links are distinguishable from body text (underline or color) | Toggle `text-decoration: none` — can you still tell? |
      
      ## Interaction & Feedback
      
      | # | Check | How to test |
      |---|-------|-------------|
      | I1 | Every clickable element has hover/active state (desktop) | Hover each button, link, icon |
      | I2 | Click/tap produces visible feedback within 100ms | Record slo-mo video or use DevTools Performance |
      | I3 | Disabled buttons are visually muted (not removed) | Check `disabled` attribute styling |
      | I4 | Loading states appear within 200ms for async operations | Slow network in DevTools, observe skeleton/spinner |
      | I5 | Keyboard navigation works: Tab → Enter/Space → Escape | Tab through entire page |
      | I6 | Focus ring is visible (≥2px, high contrast) | Tab through all interactive elements |
      | I7 | Destructive actions have confirmation or undo | Trigger delete/remove, observe |
      | I8 | Empty states have a message + action (not blank) | Clear all data, observe screen |
      | I9 | Error messages are inline, specific, and below the input | Submit invalid form |
      
      ## Accessibility
      
      | # | Check | How to test |
      |---|-------|-------------|
      | A1 | Body text contrast ≥ 4.5:1 | DevTools contrast checker or axe DevTools |
      | A2 | Large text contrast ≥ 3:1 | Same |
      | A3 | UI component contrast ≥ 3:1 (borders, icons, focus) | Same |
      | A4 | All images have `alt` text (or `aria-label` for icons) | axe DevTools or scan `img` tags |
      | A5 | Buttons and links describe action, not just appearance | "Close dialog", not "X" |
      | A6 | Heading hierarchy is correct (h1 → h2 → h3, no skipping) | `document.querySelectorAll('h1,h2,h3,h4,h5,h6')` |
      | A7 | Page uses `<nav>`, `<main>`, `<aside>` landmarks | axe DevTools |
      | A8 | Text can be resized to 200% without breaking layout | Zoom browser to 200% |
      | A9 | Pinch-zoom is not disabled (no `user-scalable=no`) | Check `<meta name="viewport">` |
      | A10 | Screen reader can complete all tasks | VoiceOver / TalkBack full flow test |
      | A11 | `prefers-reduced-motion` is respected | Enable in OS settings, check animations |
      
      ## Copy & Content
      
      | # | Check | How to test |
      |---|-------|-------------|
      | C1 | Every heading describes the content below it | Read headings in isolation |
      | C2 | Error messages are human-readable, not technical | "Something went wrong. Please try again." not "Error 0x87e5000b" |
      | C3 | CTAs use verbs ("Create account", "Save changes") | "Submit", "OK", "Click here" fail |
      | C4 | No placeholder text substitutes for a label | Labels are visible above/next to fields |
      | C5 | Numbers and dates are formatted for locale | Check currency, date format, decimal separator |
      | C6| No jargon unless the user is technical | "Authenticate", "Onboard", "Execute" fail for consumer apps |
      
      ## Motion & Animation
      
      | # | Check | How to test |
      |---|-------|-------------|
      | M1 | Every animation has a functional purpose | Remove animation — is anything broken? If not, remove it |
      | M2 | Duration ≤ 300ms for micro-interactions | Record and measure |
      | M3 | No parallax, auto-play video, or large decorative animations | Check with `prefers-reduced-motion: reduce` |
      | M4 | Page transitions are smooth (no jank, no white flash) | Navigate with slow CPU throttling |
      | M5 | Skeleton screens appear before content, not after | Observe loading sequence |
      
      ---
      
      ## Scoring
      
      - **All groups pass** → Ship it.
      - **1–2 failures in Layout, Hierarchy, or Interaction** → Fix before shipping.
      - **Any failure in Accessibility** → Blocking. Fix before shipping.
      - **3+ failures total** → Redesign pass needed.
      
    • references/playbook.md (11 KB)
      # Apple UI Playbook — Practical Design Heuristics
      
      > Generalized from Apple HIG philosophy for web apps, dashboards, onboarding flows, share-cards, and product testing tools.
      
      ---
      
      ## 1. Core Principles
      
      | # | Principle | What it means for web UI |
      |---|-----------|--------------------------|
      | 1 | **Clarity over decoration** | Every element earns its place. If it doesn't inform or enable an action, remove it. |
      | 2 | **Content-first layout** | Start with the data/user goal. Add UI around it, not the other way. |
      | 3 | **Deference** | The interface disappears when the user is focused. No chrome competes with content. |
      | 4 | **Progressive disclosure** | Show the essential now, the rest on demand. Don't dump everything on one screen. |
      | 5 | **Friction is a feature** | Make destructive/irreversible actions intentionally harder. Make primary actions frictionless. |
      | 6 | **Direct manipulation** | Let users interact with the thing itself, not a control panel for the thing. |
      | 7 | **Consistent mental model** | Same pattern = same behavior everywhere. Surprises erode trust. |
      
      **Good decision:** A dashboard card that shows key metric, trend sparkline, and one CTA button. Everything else is one click away.
      
      **Bad decision:** A dashboard card with 3 tabs, 2 dropdowns, an info icon with a tooltip, a settings gear, and an "edit" pencil — all visible at once.
      
      ---
      
      ## 2. Web-App Layout Rules
      
      ### Grid & Spacing
      - Use an 8‑point baseline grid. Margins, padding, gap — all multiples of 8 (or 4 for dense content).
      - 12‑column flexible grid for layouts wider than 768px. Collapse to 4 or 6 columns on tablet, 2 on mobile.
      - Content area max-width: 640–720px for reading, 1200px for dashboards.
      - Gutter: 24px (desktop), 16px (tablet), 16px (mobile).
      
      ### Safe Areas
      - `env(safe-area-inset-*)` for notch/home indicator on iOS WebView.
      - Sticky headers and bottom bars inset by safe area.
      - No critical content in the outer 16px on mobile (thumb zone).
      
      ### Touch Targets
      - Minimum 44×44px. 48×48px preferred.
      - Spacing between targets ≥ 8px.
      - For icon-only buttons, add invisible padding to hit 44×44 minimum.
      
      ### Visual Rhythm
      - Place primary action at bottom-right (mobile) or top-right (desktop).
      - Group related controls together. Separate unrelated controls with visible whitespace, not lines.
      - Scan direction: top-to-bottom, left-to-right. Place the most important content at top-left.
      
      **Good:** A share-card layout with hero image → metric → attribution → CTA, one after another, 24px gaps.
      
      **Bad:** A share-card with CTA at top-left, metric in the middle, hero overlapping text, and attribution in a tiny font at the bottom.
      
      ---
      
      ## 3. Design Smell Detector
      
      ### S1: Too Many Visual Weights
      - **Detect:** Count distinct font sizes, colors, and font weights on screen. If >3 of any, you have a problem.
      - **Why it hurts:** User can't tell what matters. Everything shouts = nothing shouts.
      - **Fix:** Max 3 sizes (primary, secondary, caption). Max 2 weights (regular + semibold). Max 2 accent colors + neutral.
      - **Tailwind hint:** Extract to `theme.extend.fontSize` and `theme.extend.colors`. Restrict yourself to what's in the config. If you need a new size, justify it.
      
      ### S2: Weak Hierarchy
      - **Detect:** Cover the screen title. Can you still tell what the page is about from remaining elements? If not, hierarchy failed.
      - **Why it hurts:** Scanning is slower. Users miss the point.
      - **Fix:** One hero element (headline or data point) → supporting context → secondary info → tertiary details/tools.
      - **React hint:** Render as a single `<Stack>` per section with consistent `<Heading />`, `<Body />`, `<Caption />` components. No inline style overrides.
      
      ### S3: Fake Premium Aesthetic
      - **Detect:** Over-used gradients, heavy drop shadows, multiple glassmorphism layers, bevels, and unnecessary 3D transforms on content.
      - **Why it hurts:** Looks dated and distracts from function. Users associate it with scam/marketing sites.
      - **Fix:** Flat color + one subtle shadow (elevation) per layer. One gradient accent maximum, used sparingly. Glassmorphism only on overlays, never on content cards.
      - **Tailwind hint:** Stick to `shadow-sm`, `shadow-md`, `shadow-lg`. No custom blur/gradient combos unless the brand demands it. Use `backdrop-blur-sm` at most.
      
      ### S4: Low Information Density
      - **Detect:** On a 1920px screen, content occupies <40% of the viewport width while sidebars, padding, and empty chrome take the rest.
      - **Why it hurts:** Forces scrolling for no reason. User can't get an overview.
      - **Fix:** Wider content area (up to 1200px). Reduce horizontal padding from 48px to 24px. Use multi-column layouts for data. Remove decorative sidebars.
      - **React hint:** Use a responsive grid. `grid-cols-1 md:grid-cols-2 lg:grid-cols-3` instead of a single-column stack. Test at 1280px width.
      
      ### S5: Unclear Primary Action
      - **Detect:** Ask "what should the user do on this screen?" If the answer isn't immediately obvious from the UI, primary action is unclear.
      - **Why it hurts:** Users hesitate. Conversion drops. Users click secondary/tertiary actions by mistake.
      - **Fix:** One primary CTA per viewport. Use filled/high-contrast button for it. Make it the most visually dominant interactive element. If multiple equal actions exist, the view needs restructuring.
      - **Tailwind hint:** Primary button = `bg-blue-600 text-white hover:bg-blue-700`. Secondary = `border border-gray-300`. Never two `bg-blue-600` on the same screen.
      
      ### S6: Component Soup
      - **Detect:** Same page has a table, a card grid, an accordion, tabs, a carousel, and a list — all showing similar data.
      - **Why it hurts:** Inconsistent interaction patterns. User can't build a reliable mental model of how to browse data.
      - **Fix:** Pick one container pattern per page. If data is comparable, use the same component everywhere. Differentiate only by purpose, not by visual variety.
      - **React hint:** Extract a single `<DataContainer>` component. Pass `variant="table"|"grid"|"list"` as a prop. Never mix two variants on the same page.
      
      ### S7: Spacing Inconsistency
      - **Detect:** Measure gaps between elements. If you find 8px, 12px, 14px, 20px, 32px across the same page, spacing is inconsistent.
      - **Why it hurts:** Feels sloppy. Users subconsciously perceive lower quality.
      - **Fix:** Use a spacing scale: 4, 8, 12, 16, 24, 32, 48, 64. Never use unlisted values. Apply `gap` for grid/flex, not individual margins.
      - **Tailwind hint:** Stick to `gap-2`, `gap-4`, `gap-6`, `gap-8`. Consider a lint rule banning arbitrary `m-[*]`, `p-[*]`, `gap-[*]`.
      
      ### S8: Decorative Motion
      - **Detect:** Elements animate in, bounce, spin, or pulse with no functional purpose. Especially problematic: parallax on hero images, spinning logos, auto-advancing carousels.
      - **Why it hurts:** Triggers vestibular disorders. Competes for attention. Feels unprofessional.
      - **Fix:** Every animation must serve 1 of 3 purposes: communicate state change, focus attention, or provide spatial context. If it doesn't, remove it. Respect `prefers-reduced-motion`.
      - **React hint:** Use Framer Motion's `useReducedMotion()`. Wrap decorative animations in a `<motion.div>` that checks the preference. Turn carousel auto-advance off.
      
      ### S9: Inaccessible Contrast
      - **Detect:** Run any contrast checker. Text on backgrounds below 4.5:1 fails. Large text (≥18px bold or ≥24px regular) below 3:1 fails. Interactive elements below 3:1 fail.
      - **Why it hurts:** Users with low vision can't read the screen. Legal liability in accessibility-regulated markets.
      - **Fix:** Use high-contrast text colors (`gray-900` on `white`, not `gray-500` on `white`). Never use `gray-400` or lighter for body text. Provide a dark mode that also passes contrast.
      - **Tailwind hint:** Body text = `text-gray-900 dark:text-gray-100`. Caption = `text-gray-500` minimum. Interactive elements: use `ring-offset-2 ring-blue-500` for focus, not color-only indicators.
      
      ### S10: Content Hidden Behind Pretty UI
      - **Detect:** Critical info (price, dates, status, errors) is inside expandable sections, tooltips, modals, or behind hover-only reveals.
      - **Why it hurts:** Increases cognitive load. Mobile users can't hover. Users miss critical info.
      - **Fix:** Put essential info in plain view. Use progressive disclosure for secondary/optional details only. Never hide: primary action label, cost, error messages, timestamps, confirmation state.
      - **React hint:** Always render the primary label/state visibly. Use a `title` attribute or `<span className="sr-only">` for supplementary info, never for essential content.
      
      ---
      
      ## 4. Component Decision Guide
      
      | Component | Good practice | Bad practice |
      |-----------|--------------|--------------|
      | **Primary button** | Filled, high contrast, one per viewport | Ghost button for critical action |
      | **Secondary button** | Outlined, same height as primary | Text link pretending to be a button |
      | **Navigation bar** | Title + back + one action | Breadcrumbs, search, avatar, 3 icons, and a dropdown |
      | **Tab bar** | 3–5 tabs, label + icon | 7+ tabs, icons only, no labels |
      | **Card** | Consistent elevation, full-area tappable | Random shadows, mixed corner radius, partial click target |
      | **Modal** | Single task, clear dismiss (X + Escape) | Stacked modals, no backdrop dismiss, 3+ inputs |
      | **Switch/toggle** | Immediate effect, no save button | "Save settings" required after toggle |
      | **Empty state** | Illustration + message + action | Blank screen or spinner that never ends |
      | **Error message** | Inline, specific, below the input | Toast that disappears, "An error occurred" |
      | **Search** | Autocomplete, visible input, clear button | Hidden behind icon, no suggestions, no way to clear |
      
      ---
      
      ## 5. Practical Patterns for Your Projects
      
      ### Dashboards
      - One KPI card per row on mobile, 2–3 per row on desktop.
      - Sparkline + number + one-word label. No legend unless interactive.
      - Chart tooltip: show value + label + change. Hide gridlines.
      
      ### Share/Wrapped Cards
      - Card ratio: 3:4 or 9:16 (Instagram/Story friendly).
      - Hero graphic → stat → caption → branding. No CTA inside the card.
      - Text must be readable at 320px width (the message preview size).
      
      ### Onboarding Flows
      - Max 3 steps. Each step = one concept + one action.
      - Progress bar at top. Skip link if skippable.
      - No account-required gate until the user has seen value.
      
      ### Product Testing Tools
      - Side-by-side comparison layout. Left = control, Right = variant.
      - Floating action bar at bottom: Approve / Reject / Comments.
      - Keyboard shortcuts: J/K for navigate, A/R for approve/reject.
      
      ---
      
      > Use this playbook as a reference when building UI. Pick the principle or smell that matches your current problem and apply the fix pattern.
      
    • references/reviewer.md (2.8 KB)
      You are a UI reviewer trained on Apple Human Interface Guidelines, specialized in React/Next.js/Tailwind CSS applications.
      
      Review the provided screen (code, screenshot, or description). Be concrete — no vague "make it cleaner" advice.
      
      ## Output Format
      
      ### A) Top 5 Issues
      List exactly 5 issues ranked by impact. For each:
      - **Issue**: one-line description
      - **Smell tag**: reference from Design Smell Detector (S1–S10)
      - **Severity**: critical / high / medium / low
      - **Why it hurts**: 1 sentence on user impact
      - **Evidence**: what you see on screen that confirms this issue
      
      ### B) Exact Visual Fixes
      For each issue, give an exact fix:
      - Before → After description
      - Key measurement (spacing, color, size, contrast ratio)
      - Component/selector to change
      
      ### C) Code-Level Suggestions
      React/Tailwind specifics when applicable:
      - Replace `<div className="flex...">` with `<Stack gap={4}>`
      - Extract hardcoded colors to `theme.extend.colors`
      - Add `useReducedMotion()` for animations
      - Add `sr-only` for missing labels
      - Add `focus:ring-2 focus:ring-blue-500` for focus states
      - Replace inline `style` with Tailwind utility classes
      
      ### D) What to Remove
      List elements that should be deleted, not fixed:
      - Decorative elements with no function
      - Duplicate CTAs
      - Unused state indicators
      - Redundant labels
      - Empty wrappers
      
      ### E) Final Score /10
      - 10: Apple-level polish. Ship it.
      - 8–9: Minor issues. Fix and ship.
      - 6–7: Needs rework before shipping.
      - 4–5: Major redesign needed.
      - 0–3: Start over.
      
      Include a 1-sentence justification for the score.
      
      ## Reference: Design Smell Detector
      
      Use these tags in your analysis:
      
      - **S1 Too Many Visual Weights** — >3 font sizes, >2 font weights, >2 accent colors on one screen
      - **S2 Weak Hierarchy** — page purpose unclear within 3 seconds of scanning
      - **S3 Fake Premium Aesthetic** — overused gradients, heavy shadows, glassmorphism on content cards
      - **S4 Low Information Density** — content occupies <40% of viewport at 1920px
      - **S5 Unclear Primary Action** — no dominant CTA, or multiple competing primary buttons
      - **S6 Component Soup** — multiple container patterns (table + grid + accordion) for similar data
      - **S7 Spacing Inconsistency** — gaps outside the 4/8/12/16/24/32/48/64 scale
      - **S8 Decorative Motion** — animation with no functional purpose
      - **S9 Inaccessible Contrast** — text/UI below WCAG AA thresholds
      - **S10 Content Hidden Behind Pretty UI** — critical info inside expandable/hover-only/reveal elements
      
      ## Constraints
      - Do not copy Apple wording verbatim. Use generalized heuristics.
      - Every suggestion must be actionable at code level. If you can't write the CSS/React prop for it, don't suggest it.
      - When in doubt, prefer removal over addition. Less UI solves more problems.
      
      ---
      
      Provide the review now.
      
    • references/skillset.md (14 KB)
      Here is a reusable design skillset derived from Apple’s Human Interface Guidelines, generalized for web and product design. Each section is a standalone heuristic or checklist you can apply directly.
      
      ---
      
      ## 1. Apple-Inspired UI Principles
      
      - **Clarity** – Content comes first. Every element (text, icon, control) must have a clear purpose. Avoid decorative clutter; use visual hierarchy to lead the eye.
      - **Deference** – The interface fades behind the user’s task. Transitions are smooth, controls are subtle, and content breathes with ample white space.
      - **Depth** – Use layers and motion to communicate spatial relationships. Subtle shadows, parallax, and smooth transitions help users understand where they are and what to expect next.
      - **Consistency** – Reuse familiar patterns (e.g., navigation bars, tab bars, modals) so users don’t have to relearn interactions.
      - **Direct Manipulation** – Let users touch, drag, swipe, or tap content directly. Avoid intermediary menus when a gesture or direct action is more intuitive.
      - **Feedback** – Every action should have an immediate, visible response (e.g., button highlight, state change, haptic or sound cue on mobile).
      - **Metaphor** – Use real-world analogues (e.g., a page curl, a trash can, a toggle switch) to make digital actions feel familiar.
      - **User Control** – Users initiate and control actions; avoid unexpected outcomes. Always provide an obvious way to undo or cancel.
      
      ---
      
      ## 2. Layout Rules for Web Apps
      
      - **Safe Zones** – Place critical content (actions, navigation, inputs) inside the safe area (avoid browser chrome, scrollbars, sticky headers/footers). On mobile, respect notch and home indicator areas.
      - **Responsive Spacing** – Use a consistent 8‑point grid system. Margins and padding should scale in multiples of 8 (or 4 for tight spaces). Breakpoints at 320‑480‑768‑1024‑1440px.
      - **Content‑First Width** – Text columns should be 600‑800px max for readability on large screens. Use a 12‑column flexible grid for complex layouts.
      - **Alignment** – Left‑align text for most languages; center only for short, isolated elements (headlines, buttons). Avoid right‑alignment in multi‑column layouts.
      - **Touch Targets** – Minimum 44×44px for any interactive element (buttons, links, inputs). Space between touch targets ≥ 8px.
      - **Visual Hierarchy** – Use size, weight, and color to show importance. The most important action should be the largest or most colorful (e.g., primary button).
      - **Scrolling vs. Pagination** – Prefer vertical scrolling for content feeds. Use pagination only when content is finite and navigation benefits from clear landmarks (e.g., step‑by‑step forms).
      - **Avoid Dead Zones** – Every part of the screen should either be interactive, informative, or clearly inactive. Large empty spaces without purpose confuse users.
      
      ---
      
      ## 3. Interaction and Feedback Rules
      
      - **Instant Visual Feedback** – Every tap, click, or gesture must trigger an immediate state change (hover highlight, press dim, active color). Delay >0.1s feels broken.
      - **Touch‑Friendly Gestures** – Support swipe to go back, pull‑to‑refresh, long‑press for context menus. Ensure single‑tap remains the primary action.
      - **Error Prevention & Undo** – Before destructive actions, show a confirmation or provide a short undo window (e.g., “Item deleted – Undo” toast). Don’t rely on alerts that block interaction.
      - **Loading States** – Show skeleton screens or progress indicators within 200ms. For operations >1s, show a progress bar or percentage. Never leave a user waiting without feedback.
      - **Keyboard Accessibility** – All interactive elements must be reachable and activatable via Tab, Enter, Space, and Escape. Focus order should follow visual layout.
      - **Hover States** – On desktop, provide hover tooltips for truncated text or icon meanings. Do not rely on hover for primary actions (they don’t work on touch).
      - **Drag‑and‑Drop** – Provide a clear visual indication of the dragged item, a drop target highlight, and the ability to cancel by pressing Escape or dropping outside the target.
      - **Touch and Hold** – Use for secondary actions (e.g., peek, copy, add to playlist). Provide haptic (or visual) feedback if supported.
      
      ---
      
      ## 4. Component Heuristics
      
      - **Navigation Bars** – Always show the current screen title. Use a back arrow (for iOS‑like apps) or breadcrumbs for deeper hierarchies. Keep actions limited to one primary action per bar.
      - **Tab Bars** – Place at bottom (mobile) or top (desktop). Limit to 5 tabs. Do not include “Settings” as a tab unless it’s a core function; use a gear icon in the navigation bar instead.
      - **Buttons** – Clearly differentiate primary (filled, high contrast), secondary (outlined), and tertiary (text‑only) buttons. Disabled buttons should be visually muted, not removed.
      - **Text Fields** – Show placeholder text inside the field. Use a visible label above or beside the field. Provide clear error messages in‑line (not in a toast) and keep them concise.
      - **Switches / Toggles** – Use a physical switch metaphor. Immediate action on toggle; do not require a “Save” button for toggle changes.
      - **Sliders** – Always show the current value as a number or icon. Allow tapping on a specific point to jump there, not just dragging.
      - **Cards** – Use consistent elevation (shadow) to indicate grouping. Cards should be tappable as a whole when they represent a single action or navigation target.
      - **Modals / Sheets** – Use for focused tasks (e.g., login, share, compose). Must have a clear dismiss (X, Cancel, or swipe down). Avoid stacking modals.
      - **Alerts** – Reserve for critical information that requires a decision (e.g., “Delete – Cancel”). Do not use for confirmations of non‑destructive actions (use toast or inline banner instead).
      - **Tooltips / Popovers** – Appear on hover/focus, disappear on escape or blur. Keep content short. Do not place interactive elements inside tooltips.
      
      ---
      
      ## 5. Accessibility Checklist
      
      - **Color Contrast** – All text and interactive elements must meet WCAG AA (4.5:1 for text, 3:1 for large text and UI components). Test with grayscale mode.
      - **Scalable Text** – Use relative units (rem, em) so text can be resized up to 200% without breaking layout. Never disable pinch‑zoom on mobile.
      - **Screen Reader Labels** – Every image must have `alt` text (or `aria‑label` for icons). Buttons and links must describe their action (e.g., “Close dialog” not just “X”).
      - **Focus Indicators** – Provide a visible focus ring (outline) for keyboard navigation. Custom focus styles must be at least 2px wide and high contrast.
      - **Touch Targets** – Minimum 44×44px, even for small icons. Provide extra padding or a larger invisible hit area.
      - **Headings & Landmarks** – Use proper HTML heading hierarchy (h1–h6) and `<nav>`, `<main>`, `<aside>` landmarks for screen reader navigation.
      - **Motion Reduction** – Respect `prefers‑reduced‑motion`. Turn off auto‑play video, parallax, and large animations. Use `transform` and `opacity` for performant, accessible transitions.
      - **VoiceOver / TalkBack** – Test all flows with screen reader on. Ensure custom controls (switches, sliders, drag‑and‑drop) are announced and operable with gestures.
      - **High Contrast / Dark Mode** – Support system‑level appearance settings. Invert colors or provide a separate high‑contrast theme.
      - **Error Announcements** – Use `aria-live` regions to announce dynamic validation errors to screen readers without losing focus.
      
      ---
      
      ## 6. Product Review Checklist
      
      1. **Purpose & Clarity** – Does every screen have a clear primary goal? Can a new user understand what to do in <5 seconds?
      2. **Visual Consistency** – Check typography, color palette, spacing, icon style across all screens. Are all elements using the same design tokens?
      3. **Responsiveness** – Test on three breakpoints: mobile (375px), tablet (768px), desktop (1280px). Any overlapping, hidden, or misaligned elements?
      4. **Navigation Flow** – Can the user complete the main task (e.g., purchase, sign up, search) in ≤3 taps/clicks? Is there a clear “home” or escape?
      5. **Loading & Empty States** – Are skeletons/placeholders shown? What happens when a list is empty (friendly message + action)?
      6. **Error Handling** – What appears when network fails? Are error messages helpful and non‑technical (“Oops, something went wrong. Please try again.”)?
      7. **Forms & Inputs** – Are validation errors shown inline? Are required fields marked? Is autocomplete enabled for common fields (email, phone)?
      8. **Feedback & Haptics** – Does every action produce immediate visual feedback? On mobile, are haptic patterns used for success, error, and selection?
      9. **Performance** – Do major interactions feel instant (<100ms)? Are images lazy‑loaded? Does scrolling feel smooth (no jank)?
      10. **Accessibility** – Run through checklist #5. Can all tasks be completed using only keyboard and screen reader?
      
      ---
      
      ## 7. React/Next.js Implementation Advice
      
      - **Use a Design System** – Implement Apple‑inspired components as a library (Storybook / Bit) with shared tokens (spacing, colors, typography). Use Tailwind CSS or CSS‑in‑JS to enforce consistency.
      - **Safe Area Handling** – Use `env(safe-area-inset-*)` in CSS for notch / home indicator. In Next.js, apply via a `safeArea` utility class on `body`.
      - **Layout Components** – Create reusable `<SafeAreaView>`, `<Stack>` (flex column), `<HStack>` (flex row), `<Spacer>` wrappers with consistent margin/padding based on 8px grid.
      - **Motion Library** – Use Framer Motion for transitions (page transitions, modal slides, skeleton shimmer). Respect `prefers-reduced-motion` with `useReducedMotion()`.
      - **Keyboard Navigation** – Add `tabIndex` to custom components. Use `useFocusWithin` or `useEventListener` for managing focus traps in modals.
      - **Server Components** – Keep interactive UI (buttons, inputs, modals) as client components. Use server components for static content (layout headers, product lists) to improve performance.
      - **Progressive Enhancement** – Ensure the app works without JavaScript (basic HTML forms, links, static content). Use `<noscript>` fallbacks and meta refresh for legacy browsers.
      - **Image Optimization** – Use Next.js `next/image` with `priority` on above‑the‑fold images. Implement lazy loading for the rest. Provide `alt` text automatically from content.
      - **Accessibility Hooks** – Create a `useAriaLive()` hook for dynamic announcements. Wrap actions in `aria-live=“polite”` when needed. Use `@radix-ui/react-dialog` for accessible modals (focus trap, escape dismiss).
      - **Testing** – Use Playwright or Testing Library to simulate keyboard and screen reader flows. Write tests for every interactive component (focus, click, screen reader label).
      
      ---
      
      ## 8. “Bad UI Smell” List
      
      - **Over‑crowded screens** – More than 5 interactive elements in a single row without clear grouping. Too many text styles or colors.
      - **No visible feedback** – Buttons that don’t change state on click. Forms that submit without any success/error signal.
      - **Hidden navigation** – No back button, no breadcrumbs, no indication of where the user is in the app hierarchy.
      - **Tiny touch targets** – Buttons or links smaller than 44×44px, especially next to each other.
      - **Unclear “sign off”** – No log out, delete account, or profile exit path. Users feel trapped.
      - **Placebo “Save” buttons** – A “Save” button that doesn’t save automatically when toggles or switches change state (unless explicitly required by UX).
      - **Inconsistent iconography** – Same icon used for two different actions (e.g., a star for both favorites and ratings).
      - **Alerts for everything** – Warnings popping up for trivial actions (like “Are you sure you want to go back?” on a form with empty fields).
      - **Disappearing elements** – Tooltips or dropdowns that close when you move the cursor slightly off them.
      - **Missing loading states** – No skeleton, spinner, or progress bar for operations taking >200ms. Blank screen while data loads.
      - **No keyboard support** – Unable to Tab through a form, or pressing Enter doesn’t submit. Focus ring invisible or missing.
      - **Over‑engineered gestures** – Swipe left to delete, swipe right to reorder, long‑press to edit, pinch to zoom – but no visual cues or discoverability.
      - **Color as only indicator** – Using only red/green to show success/error without text or icon. Accessibility nightmare.
      - **Infinite scroll without progress** – User scrolls forever but never knows how many items remain or where they are.
      - **Mode without exit** – A full‑screen onboarding, tutorial, or full‑screen modal that cannot be dismissed (no X or back).
      
      ---
      
      ## 9. Reusable Agent Prompt for Reviewing Screens
      
      ```
      You are a UI reviewer trained on Apple Human Interface Guidelines. Review the provided screen design (image or code) and produce a critique using the following structure:
      
      1. **Overall Impression** (1 sentence): Is the UI clear, clean, and well‑organized?  
      2. **Layout & Alignment** (bullet list):  
         - Check safe area, spacing, grid consistency, responsive breakpoints.  
         - Is content prioritized with visual hierarchy?  
      3. **Interaction & Feedback** (bullet list):  
         - Identify missing or delayed feedback on actions.  
         - Are touch targets ≥44px? Are gestures discoverable?  
      4. **Component Usage** (bullet list):  
         - Are buttons, navigation, modals, and alerts used appropriately?  
         - Check for inconsistencies (e.g., primary button vs. link).  
      5. **Accessibility** (bullet list):  
         - Color contrast, focus indicators, screen reader labels, keyboard navigation.  
      6. **Bad Smells**: List any of the “Bad UI Smells” present.  
      7. **Top 3 Improvements**: Prioritize the most impactful changes.
      
      Always reference Apple‑inspired principles (Clarity, Deference, Depth, Direct Manipulation) when explaining why something works or fails.
      ```
      
      ---
      
      This skillset can be used as a living document, adapted for any web or product design team. The heuristics are intentionally general (not tied to iOS) but carry the core philosophy of Apple’s HIG: **design with the user’s mental model, not the system’s.**
  • architect

    Sketch types, signatures, and module structure before code, then stay in the loop while implementation fills in. Use for /architect, 'architect this', 'design this', or non-trivial work where jumping to code would lock in the wrong shape.

    • SKILL.md (5.5 KB)
      ---
      name: architect
      description: "Sketch types, signatures, and module structure before code, then stay in the loop while implementation fills in. Use for /architect, 'architect this', 'design this', or non-trivial work where jumping to code would lock in the wrong shape."
      disable-model-invocation: true
      ---
      
      # Architect
      
      Design before implementing. Sketch types, function signatures, class shapes, and module boundaries with `not implemented` bodies and pseudocode. Synthesize across multiple model perspectives, then fill in code against the chosen sketch. If implementation proves the sketch wrong, throw it out and redesign.
      
      ## Start
      
      Open a todolist with one entry per phase before starting.
      
      1. Ground
      2. Sketch
      3. Agree
      4. Implement
      5. Scrap
      
      ## Phase A: Ground the problem
      
      Build a real mental model of every system the new code touches. Run the **how** skill over the relevant subsystems.
      
      Naming a file isn't grounding. Produce the traced model `how` prescribes. If the design redefines ownership or layering, also run the **why** skill on the existing shape so the rationale becomes a constraint, not a guess.
      
      Skip Phase A only when the work is genuinely greenfield with no surrounding system to integrate.
      
      ## Phase B: Sketch
      
      Run the **arena** skill with the design-sketch task and the Phase A grounding artifacts. Pass `references/runner-prompt.md` as each runner's prompt. Each candidate produces a design package shaped per `references/rationale-template.md`.
      
      Take the runners from the `architect runners` line in the `pstack-models.mdc` rule, in place of the `arena runners` line. If the rule or that line is missing, use `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast`. Alias and rejected entries follow the runner rules in the **arena** skill's Phase A.
      
      Design it twice. Require at least two structurally distinct candidates before synthesis, even when the first looks sufficient. This is the **exhaust-the-design-space** principle skill made concrete. Whole-shape alternatives, not point fixes inside one shape.
      
      Screen every candidate against [`references/design-red-flags.md`](references/design-red-flags.md) before synthesis. Assume the next contributor is an agent that sees only the files it opened, copies the nearest example, and takes the shortest path that compiles. Prefer the design where a change that looks right from one file is right for the whole repo.
      
      Compare viable candidates on interface depth. Prefer the design that hides more complexity behind a smaller, simpler public surface. A rich interface can keep call chains short by concentrating capability instead of scattering it across layers.
      
      Arena returns one synthesized design package. The synthesis decision populates the rationale's "Synthesis decision" section.
      
      ## Phase C: Agree (opt-in)
      
      Default: proceed directly to implementation with the synthesized design. No human checkpoint.
      
      Opt in to a checkpoint when the invoker explicitly asks: "/architect with checkpoint," "stop and show me before implementing," or similar. Then surface the synthesized design and pause for sign-off.
      
      The synthesis can ship as its own commit either way, as the "scaffold first" mode of the **foundational-thinking** principle skill. Planned and scoped breakage during fill-in is fine, per the **outcome-oriented-execution** principle skill. For adversarial pressure on the design before implementing, run the **interrogate** skill on the synthesized sketch.
      
      If the human pushes back on the shape (in a checkpoint or after the fact), treat that as Phase A evidence. Re-ground and re-run Phase B before writing more code.
      
      ## Phase D: Implement against the sketch
      
      Replace `not implemented` bodies with code, pseudocode with logic. The synthesized sketch is the contract.
      
      Deviations from the sketch are signal worth surfacing, not friction to absorb silently. If a function needs a parameter the sketch didn't anticipate, ask whether the sketch was wrong, the requirement was missed, or the implementation is overreaching.
      
      ## Phase E: Scrap when the architecture is wrong
      
      If implementation keeps producing friction the sketch can't absorb, throw the sketch out. Don't bolt fixes onto a wrong design, per the **redesign-from-first-principles** and **fix-root-causes** principle skills.
      
      The signal is a *pattern*, not single instances. Tells:
      
      - The same shape of workaround appearing repeatedly across unrelated code.
      - Multiple unrelated edge cases that all need special-case branches.
      - Types that need escape hatches (`any`, casts, optional fields always set in practice) to compile.
      - The "we need a lock" reflex when the sketch said the state wasn't shared.
      - Callers having to know the abstraction's internal rules to use it.
      - Two or more independent Phase D deviations of the same shape across the implementation.
      
      Use judgment. A few edge cases don't condemn an architecture. Some problems are legitimately complex. Complexity in the data is not complexity in the design.
      
      When you scrap:
      
      1. Re-run the **how** skill over what's been built.
      2. Redesign as if the new constraints had been day-one assumptions, per redesign-from-first-principles.
      3. Subtract before adding, per the **subtract-before-you-add** principle skill. The new sketch should be smaller than the old one before it grows.
      4. Return to Phase B and re-run arena.
      
      ## Outputs
      
      The caller's usage is written first and the type sketch derived from it. One file with new types and signatures for small changes. Module map plus type definitions for larger work. The rationale ships alongside, shaped per `references/rationale-template.md`, including the usage sketch and the synthesis decision.
      
    • references/design-red-flags.md (2.9 KB)
      # Design red flags
      
      Screen every candidate before synthesis. A red flag is a reason to revise or reject the shape.
      
      ## Shallow module
      
      A shallow module exposes a large interface while hiding little complexity. Judge depth by the capability and policy hidden behind the public surface relative to the size of that surface. Prefer a simple interface backed by substantial behavior.
      
      Do not confuse a deep module with a deep call chain. A deep call chain scatters understanding across layers. A deep module concentrates capability behind one interface.
      
      Look for these signs:
      
      - Callers coordinate several methods to complete one operation.
      - Public options expose internal stages or implementation choices.
      - Learning the interface does not save the caller from learning the implementation.
      
      ## Information leakage
      
      Information leakage makes multiple modules depend on the same internal decision. A representation, policy, or protocol detail appears in more than one place, so changing it requires coordinated edits.
      
      Public re-exports of transport or wire types are leakage. Parse external data into domain types behind the interface. Keep storage schemas, framework objects, and protocol details private.
      
      ## Temporal decomposition
      
      Temporal decomposition organizes modules by execution order instead of the knowledge they own. Separate load, validate, transform, and save stages often repeat one representation and its invariants across several boundaries.
      
      Group code around domain knowledge and ownership. Methods that run at different times can still belong to one module when they protect the same decisions.
      
      ## Pass-through method
      
      A pass-through method forwards the same arguments to another method with the same shape. It adds a layer without hiding complexity.
      
      Remove it or move responsibility to the module that can complete the operation. Keep a forwarding boundary only when it adds policy, adaptation, or a distinct abstraction.
      
      ## Split ownership
      
      More than one module writes the same state or keeps its own copy of it. An agent that edits one writer can't see the others, so their rules diverge.
      
      Give each piece of state one owner. Other modules read it or ask the owner to change it.
      
      ## Two ways to do one task
      
      The design supports more than one way to do the same task. An agent copies whichever way it finds first, so every way keeps gaining callers.
      
      Keep one way. Move callers off the others and delete them in the same change.
      
      ## Importable internals
      
      A caller can import a module's internals. An agent takes the shortest path that compiles, so it imports them directly and they become part of the interface.
      
      Make internals unreachable from outside the module, so an import from outside fails the build.
      
      ## Hand-synced list
      
      Two or more places list the same items, and adding an item means editing every list. An agent that sees one list updates only that one.
      
      Keep one list and derive the others from it. If a list can't be derived, make the build fail when the lists disagree.
      
    • references/rationale-template.md (3.0 KB)
      # Rationale template
      
      The prose that ships alongside the type sketch. One page. Sentence-case headings, no boilerplate. Replace the italic notes with actual content.
      
      ## Problem
      
      *One paragraph. What we're trying to do, and what about the existing system or constraints makes the shape non-obvious. If [Phase A](../SKILL.md#phase-a-ground-the-problem) surfaced constraints the design must honor (existing types to interop with, callers we can't break, invariants that crossed our boundary), name them here so the reader sees the same constraints you saw.*
      
      ## Usage (caller's view)
      
      *Write this first, before the type sketch. Show the README or quickstart the consumer reads, plus two or three realistic call sites in their own code. What they import, what they call, what comes back. The type sketch in [Shape](#shape) is derived from this. The two must agree. When they diverge, reconcile the sketch to the usage, not the reverse. The caller's experience is the spec. The types serve it.*
      
      ## Shape
      
      *The recommended architecture. Data structures first. Then how data flows through the signatures. Name the load-bearing decisions. State which invariants are encoded in types, where validation lives, and what the system deliberately does not do. Judge interface depth explicitly. State what complexity the public surface hides, what remains exposed to callers, and why the interface is no larger than needed. Cite the principle behind each decision (e.g., `per boundary-discipline`). Don't restate it.*
      
      ## Synthesis decision
      
      *Filled in by [arena](../../arena/SKILL.md). Records which candidate became the base and why, what was adapted from each of the others, and what was rejected and why.*
      
      ## Tradeoffs accepted
      
      *One bullet per tradeoff the chosen shape makes. Form: "we accept X in exchange for Y." Name anything a future reader might mistake for an oversight, including things that look like premature optimization or premature simplification.*
      
      ## Alternatives considered
      
      *Required. Name at least one concrete alternative shape, with one line on why it lost. Judge each alternative on interface depth, not implementation simplicity alone. Name the complexity it exposes to callers and the complexity it hides. Two or three alternatives belong here when the design space had real contenders. One is fine when the constraints forced the answer, with the conclusion phrased as "this was the only viable shape because..." Avoid listing flavors of the same shape. This section covers design alternatives the chosen shape considered and rejected, not other runner candidates.*
      
      ## Open questions and risks
      
      *Things you noticed during the sketch that the human needs to weigh in on, and risks worth flagging before implementation starts. Phrase as questions, not assertions, so the human's answer is the resolution rather than a comment.*
      
      ## Next implementation step
      
      *The first thing to build against the sketch. One sentence. What you'd start writing immediately after synthesis (or after Phase D sign-off, if a checkpoint was opted into).*
      
    • references/runner-prompt.md (3.0 KB)
      # Architect runner prompt
      
      The orchestrator passes this file through to every parallel candidate runner during Phase B and fills in the variable inputs around it: the task, the Phase A grounding artifacts, the isolated working directory, and the path to write outputs. The working directory is a git worktree when available, otherwise a per-runner subdirectory under the sketch dir. What matters is independence between candidates.
      
      You are producing one candidate design in architect's parallel exploration. Read the **architect** skill in full first. That's the workflow you're inside. Output a candidate design package: type sketch, function signatures, module map, and prose rationale shaped per [`rationale-template.md`](rationale-template.md).
      
      Apply the following discipline. The orchestrator compares candidates on these axes to pick a base.
      
      - Caller's usage first. Write the README-style usage and two or three real call sites before the types, then derive the type sketch from them. The usage is the spec. The two must agree, so reconcile the sketch to the usage, not the reverse.
      - Data structures first. Get the core types right and the code becomes obvious. Trace each dominant access pattern through the proposed structure. If the answer is "we'll add a map / index / cache later," the structure is wrong.
      - Interface depth. Compare the capability hidden behind the public surface relative to the size of that surface. Prefer a simple interface that pulls complexity into the callee, even when the implementation becomes less simple. Do not put transport or wire types on the public API. Parse into domain types behind the interface.
      - Shared state: if two actors might both write, ask "what happens?" If the answer isn't "nothing," default to per-actor state with a merge at the read boundary, per the **separate-before-serializing-shared-state** principle skill.
      - Make boundaries visible. `not implemented` errors for bodies, `// TODO` pseudocode for tricky logic, doc comments stating intent and invariants. A reader should trace data from input to output by reading types and signatures alone.
      - Encode invariants in types: hard-to-misuse types > runtime checks > prose comments, per the **encode-lessons-in-structure** principle skill.
      - Validate at boundaries, trust types inside, per the **boundary-discipline** principle skill. Business logic as pure functions. The shell stays thin.
      - Single source of truth per invariant. Derive instead of sync.
      - Idempotent state transitions where applicable, per the **make-operations-idempotent** principle skill. Ask what happens if the operation runs twice or crashes halfway.
      - Short call chains. If tracing the flow needs more than three files, flatten the hierarchy, per the **laziness-protocol** and **minimize-reader-load** principle skills.
      
      You are one of the parallel runners, each on a different model. Produce the best design your model can make. Don't hedge against the others. Differences between candidates are the signal used to pick a base and graft. Converging on a safe-looking middle defeats the exploration.
      

MCP servers12

  • cloudflarehttp

    https://mcp.cloudflare.com/mcp

  • cloudflare-ai-gatewayhttp

    https://ai-gateway.mcp.cloudflare.com/mcp

  • cloudflare-bindingshttp

    https://bindings.mcp.cloudflare.com/mcp

  • cloudflare-docshttp

    https://docs.mcp.cloudflare.com/mcp

  • cloudflare-observabilityhttp

    https://observability.mcp.cloudflare.com/mcp

Settings126

antigravity

  • model="Gemini 3.8 Flash (High)"
  • permissions.allow=
    ["command(mkdir)","command(ls)","command(cat)","command(for d in /tmp/yarimci-re...
    [
      "command(mkdir)",
      "command(ls)",
      "command(cat)",
      "command(for d in /tmp/yarimci-research/repos/*; do echo \"=== $d ===\"; git -C \"$d\" remote -v 2>/dev/null; git -C \"$d\" log -n 1 --oneline 2>/dev/null; done)",
      "command(echo)",
      "command(head)",
      "command(python3 /tmp/yarimci-research/write_doc.py)",
      "command(sleep)",
      "command(git clone)",
      "command(ls -lh ~/Dev/clipsmith/in/ ~/Downloads/*.{mp4,mov,mkv,MP4,MOV} 2>/dev/null)",
      "command(ffprobe)"
    ]
  • toolPermission="always-proceed"

antigravity:hooks.json

  • herdr.PreInvocation=[{"command":"bash '${home}/.gemini/config/hooks/herdr-agent-state.sh' session","timeout":10,"type":"command"}]

claude

  • env.ENABLE_TOOL_SEARCH="true"
  • permissions.defaultMode="auto"
  • model="opus[1m]"
  • hooks.PermissionRequest=[{"matcher":"*","hooks":[{"type":"command","command":"if [ -x '${home}/.config/orca/agent-hooks/claude-hook.sh' ]; then /bin/sh '${home}/.config/orca/agent-hooks/claude-hook.sh'; fi"}]}]
  • hooks.PostToolUse=
    [{"hooks":[{"type":"command","command":"node \"${home}/.claude/hooks/gsd-context...
    [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"${home}/.claude/hooks/gsd-context-monitor.js\""
          }
        ]
      },
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "if [ -x '${home}/.config/orca/agent-hooks/claude-hook.sh' ]; then /bin/sh '${home}/.config/orca/agent-hooks/claude-hook.sh'; fi"
          }
        ]
      }
    ]

codex

  • model="gpt-6.1-sol"
  • model_reasoning_effort="medium"
  • plan_mode_reasoning_effort="max"
  • approvals_reviewer="user"
  • service_tier="default"

codex:hooks.json

  • hooks.SessionStart=[{"hooks":[{"command":"bash '${home}/.codex/herdr-agent-state.sh' session","timeout":10,"type":"command"}]}]

cursor

  • permissions.allow=["Shell(ls)"]
  • permissions.deny=[]
  • editor.vimMode=false
  • display.showLineNumbers=false
  • display.showThinkingBlocks=false

cursor-user:settings.json

  • "workbench.colorTheme"="Omarchy"
  • "workbench.preferredDarkColorTheme"="Omarchy"
  • "workbench.preferredLightColorTheme"="Omarchy"
  • "window.autoDetectColorScheme"=false
  • "cursor.composer.conversationDensity"="compact-ungrouped"
  • "update.releaseTrack"="dev"

cursor:hooks.json

  • hooks.sessionStart=[{"command":"bash '${home}/.cursor/herdr-agent-state.sh' session"},{"command":"./hooks/global-rules.sh"}]
  • version=1

grok

  • ui.max_thoughts_width=120
  • ui.fork_secondary_model="grok-4.6"
  • ui.yolo=false
  • ui.compact_mode=false
  • ui.permission_mode="always-approve"

opencode

  • "$schema"="https://opencode.ai/config.json"
  • theme="system"
  • autoupdate=false

pi

  • theme="omarchy-system"
  • quietStartup="header"
  • packages=["npm:pi-subagents@0.78.0","../../.omp/agent/extensions/observational-memory"]
  • defaultProvider="xai"
  • defaultModel="grok-4.7"

Plugins16

  • browser@openai-bundledfor Codex

  • code-review@openai-bundledfor Codex

  • codex-app-tools@openai-bundledfor Codex

  • documents@openai-primary-runtimefor Codex

  • pdf@openai-primary-runtimefor Codex

Files45

  • claude:hooks

    • herdr-agent-state.sh (3.0 KB)
      #!/bin/sh
      # installed by herdr
      # managed by herdr; reinstalling or updating the integration overwrites this file.
      # add custom hooks beside this file instead of editing it.
      # HERDR_INTEGRATION_ID=claude
      # HERDR_INTEGRATION_VERSION=10
      
      set -eu
      
      action="${1:-}"
      hook_input_file="$(mktemp "${TMPDIR:-/tmp}/herdr-claude-hook.XXXXXX")" || exit 0
      trap 'rm -f "$hook_input_file"' EXIT HUP INT TERM
      cat >"$hook_input_file" 2>/dev/null || true
      
      case "$action" in
        session) ;;
        *) exit 0 ;;
      esac
      
      [ "${HERDR_ENV:-}" = "1" ] || exit 0
      [ -n "${HERDR_SOCKET_PATH:-}" ] || exit 0
      [ -n "${HERDR_PANE_ID:-}" ] || exit 0
      command -v python3 >/dev/null 2>&1 || exit 0
      
      HERDR_ACTION="$action" HERDR_HOOK_INPUT_FILE="$hook_input_file" python3 - <<'PY'
      import json
      import os
      import random
      import socket
      import time
      
      source = "herdr:claude"
      action = os.environ.get("HERDR_ACTION", "")
      pane_id = os.environ.get("HERDR_PANE_ID")
      socket_path = os.environ.get("HERDR_SOCKET_PATH")
      hook_input_file = os.environ.get("HERDR_HOOK_INPUT_FILE")
      
      if not pane_id or not socket_path:
          raise SystemExit(0)
      
      hook_input = {}
      if hook_input_file:
          try:
              with open(hook_input_file, encoding="utf-8") as handle:
                  content = handle.read()
              if content.strip():
                  hook_input = json.loads(content)
          except Exception:
              hook_input = {}
      
      if "CURSOR_VERSION" in os.environ or "cursor_version" in hook_input:
          raise SystemExit(0)
      hook_event_name = str(hook_input.get("hook_event_name") or "")
      if hook_event_name != "SessionStart":
          raise SystemExit(0)
      is_subagent = bool(hook_input.get("agent_id"))
      if is_subagent:
          raise SystemExit(0)
      request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}"
      report_seq = time.time_ns()
      session_id = hook_input.get("session_id")
      agent_session_id = session_id if isinstance(session_id, str) and session_id else None
      transcript_path = hook_input.get("transcript_path")
      agent_session_path = transcript_path if isinstance(transcript_path, str) and transcript_path else None
      session_start_source = hook_input.get("source") if hook_event_name == "SessionStart" else None
      if not isinstance(session_start_source, str) or not session_start_source:
          session_start_source = None
      if agent_session_id:
          params = {
              "pane_id": pane_id,
              "source": source,
              "agent": "claude",
              "seq": report_seq,
              "agent_session_id": agent_session_id,
          }
          if agent_session_path:
              params["agent_session_path"] = agent_session_path
          if session_start_source:
              params["session_start_source"] = session_start_source
          request = {
              "id": request_id,
              "method": "pane.report_agent_session",
              "params": params,
          }
      else:
          raise SystemExit(0)
      
      try:
          client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
          client.settimeout(0.5)
          client.connect(socket_path)
          client.sendall((json.dumps(request) + "\n").encode())
          try:
              client.recv(4096)
          except Exception:
              pass
          client.close()
      except Exception:
          pass
      PY
      
  • claude:keybindings.json

    • keybindings.json (346 B)
      {
        "$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
        "$docs": "https://code.claude.com/docs/en/keybindings",
        "bindings": [
          {
            "context": "Global",
            "bindings": {
              "escape": null
            }
          },
          {
            "context": "Chat",
            "bindings": {
              "escape": null
            }
          }
        ]
      }
  • codex:rules

    • default.rules (2.5 KB)
      prefix_rule(pattern=["pi", "--print", "--no-session", "--no-extensions", "--no-skills", "--no-prompt-templates", "--tools", "read,grep,find,ls", "@/tmp/pi-recent-sessions-brief.md"], decision="allow")
      prefix_rule(pattern=["node", "/home/semihmutlu/dev/summer-2026/presentation/verify.cjs"], decision="allow")
      prefix_rule(pattern=["node", "/home/semihmutlu/dev/summer-2026/yaz-masasi/verify.cjs"], decision="allow")
      prefix_rule(pattern=["codex", "--version"], decision="allow")
      prefix_rule(pattern=["/home/semihmutlu/.local/share/mise/installs/codex/0.158.0/bin/codex", "doctor"], decision="allow")
      prefix_rule(pattern=["omarchy-shell", "media", "status"], decision="allow")
      prefix_rule(pattern=["python", "/tmp/fix-default-codex.py", "--apply"], decision="allow")
      prefix_rule(pattern=["bash", "/tmp/omarchy-widget-upgrade/install-media.sh"], decision="allow")
      prefix_rule(pattern=["omarchy", "pkg", "add", "gnome-calendar", "gnome-online-accounts-gtk"], decision="allow")
      prefix_rule(pattern=["systemctl", "--failed", "--no-pager"], decision="allow")
      prefix_rule(pattern=["ps", "-eo", "pid,ppid,stat,pcpu,pmem,rss,etime,comm", "--sort=-pcpu"], decision="allow")
      prefix_rule(pattern=["/usr/bin/bash", "-lc", "herdr status; herdr workspace list; herdr api snapshot; herdr session list; herdr pane read --help; herdr pane process-info --help; herdr --version; /usr/bin/time -f 'snapshot_elapsed=%e' herdr api snapshot >/dev/null"], decision="allow")
      prefix_rule(pattern=["/usr/bin/bash", "-lc", "for pane in w7X:p1 w84:p1 w85:p1 w86:p1; do herdr pane process-info --pane \"$pane\"; herdr pane read \"$pane\" --lines 22 --format text; done; for attempt in 1 2 3; do time herdr workspace list >/dev/null; done; vmstat 1 4; ps -eo pid,ppid,stat,pcpu,pmem,rss,etime,comm --sort=-pcpu | head -15"], decision="allow")
      prefix_rule(pattern=["herdr", "status"], decision="allow")
      prefix_rule(pattern=["omarchy-shell", "shell", "listPlugins"], decision="allow")
      prefix_rule(pattern=["env", "OMARCHY_PATH=/usr/share/omarchy", "omarchy-shell", "shell", "listPlugins"], decision="allow")
      prefix_rule(pattern=["env", "OMARCHY_PATH=/usr/share/omarchy", "omarchy-shell", "semihmutlu.ghost", "probe"], decision="allow")
      prefix_rule(pattern=["grim", "/tmp/ghost-desktop-audit-20261012.png"], decision="allow")
      prefix_rule(pattern=["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=8", "-o", "StrictHostKeyChecking=yes", "desktop", "hostname; omarchy version; omarchy theme current; fc-match sans-serif; fc-match serif; fc-match monospace"], decision="allow")
      
  • cursor:hooks

    • global-rules.sh (307 B)
      #!/bin/bash
      # Injects ~/.cursor/rules/*.mdc bodies as session context (CLI ignores ~/.cursor/rules).
      cat >/dev/null
      body=$(for f in "$HOME"/.cursor/rules/*.mdc; do awk 'BEGIN{n=0} /^---$/{n++; next} n>=2' "$f"; done)
      jq -n --arg c "User global rules (from ~/.cursor/rules):
      $body" '{additional_context:$c}'
      
  • cursor:rules

    • global.mdc (1.0 KB)
      ---
      description: Semih global rules
      alwaysApply: true
      ---
      - Start every nontrivial task with /poteto-mode (skill poteto-mode) and pick the matching playbook.
      - Never block on the human for reversible work: do it, verify it, show proof. Ask only before irreversible or external actions (publish, send, buy, deploy, delete).
      - Resuming work: use session-pickup. Stopping: use pause-safely.
      - Do not change model or routing settings.
      - Canary word: KIRAZ-370.
      
      ## Notion workspace
      
      When working with the user's projects, tasks, notes or
      persistent knowledge, first read:
      
      https://app.notion.com/p/3f84b6f58b3b8154a46ddd4bb6605958
      
      Use the existing Notion databases defined there.
      
      - Search before creating anything.
      - Prefer updating an existing record.
      - Do not save every conversation automatically.
      - Keep code and raw execution logs in their original sources.
      - Never delete, merge, or move records without approval.
      - Verify Notion writes before reporting completion.
      
      If Notion MCP is unavailable, report the limitation.