Skip to content
Back to skills

Goke

ASecurity

goke is a zero-dependency, type-safe CLI framework for TypeScript. CAC replacement with Standard Schema support (Zod, Valibot, ArkType). Use goke when building CLI tools — it handles commands, subcommands, options, type coercion, help generation, and more. Schema-based options give you automatic type inference, coercion from strings, and help text generation. Pair with `@goke/mcp` to generate CLI commands automatically from an MCP server. ALWAYS read this skill when a repo uses goke for its CLI.

  • 44 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
toolstypescriptgoshellbashsqlnodetestinggitapi

Works with

  • claude code
  • cursor
  • terminal
  • cli
  • api
  • mcp

Security analysis

A92/100
  • mediumUses curl or wget to download content
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned November 7, 2026

npx -y skills add remorses/opencode-config --skill goke --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Goke?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Goke
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/remorses-goke/badge)](https://www.skillsdirectory.com/skills/remorses-goke)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: goke
description: >
  goke is a zero-dependency, type-safe CLI framework for TypeScript. CAC replacement
  with Standard Schema support (Zod, Valibot, ArkType). Use goke when building CLI
  tools — it handles commands, subcommands, options, type coercion, help generation,
  and more. Schema-based options give you automatic type inference, coercion from
  strings, and help text generation. Pair with `@goke/mcp` to generate CLI
  commands automatically from an MCP server. ALWAYS read this skill when a repo
  uses goke for its CLI.
version: 0.0.1
---

# goke

Fetch the full README from GitHub and read it before using goke:

```bash
curl -L https://raw.githubusercontent.com/remorses/goke/main/README.md
```

> Read the README in full every time you use goke.
>
> Important: never use `head` or `tail` to truncate it. Read the full README instead.

## Install

```bash
npm install goke # or bun, pnpm, etc
```

## Quick Notes

- Core APIs: `cli.option`, `cli.use`, `cli.section`, `cli.version`, `cli.help`, `cli.completions`, `cli.parse`
- Prefer injected `{ fs, console, process }` over globals
- Use relative paths with injected `fs`; if a helper needs current-cwd semantics, pass injected `process.cwd` into that helper
- For JustBash compatibility tests, import the existing CLI from app code instead of defining a new CLI inside the test
- **Never install `picocolors`, `chalk`, `kleur`, or any color library.** Use `import { colors } from 'goke'` instead. It's a vendored picocolors with zero extra dependencies.
- Use [`@goke/mcp`](https://github.com/remorses/goke/tree/main/mcp) to generate CLI commands from an MCP server. `addMcpCommands({ cli, getMcpUrl, loadCache, saveCache })` discovers tools and registers a typed command for each one.

The README is the source of truth for rules, examples, testing patterns, JustBash integration, and API details.

## Reporting goke bugs

If you find a bug in goke, **always open a GitHub issue with the `gh` CLI**. Do not only mention it in chat.

```bash
gh issue create --repo remorses/goke --title "Short bug title" --body "$(cat <<'EOF'
**Model:** grok-4.6
**Harness:** OpenCode / Kimaki

**What happened**
Describe the unexpected behavior.

**Relevant goke code**
Paste the CLI definition or goke API usage from this package that triggered the bug.

**Reproduction**
Minimal example that fails:

```ts
import { goke } from 'goke'

const cli = goke('mycli')
cli.command('deploy', 'Deploy').action(() => {})
cli.parse()
```
EOF
)"
```

Always include in the issue body:

- the **model** used (for example `grok-4.6`, `claude-opus-4-6`)
- the **harness** (for example OpenCode, Claude Code, Cursor, Codex)
- the **relevant goke code** from this package that hit the bug
- a **minimal reproduction** example

If the README or this skill mentions a `goke` export that is missing from the installed package, upgrade `goke` to latest first before adding workarounds or custom local detection code:

```bash
pnpm update goke --latest
```

Use the project package manager for the repo you are editing. After upgrading, re-check the export from the installed package and continue with the documented API.

## Terminal Colors

**Never install a separate color library.** goke vendors picocolors and exports it as `colors`:

```ts
import { colors } from 'goke'

console.log(colors.green('success'))
console.log(colors.red('error'))
console.log(colors.bold(colors.cyan('info')))
```

Available formatters: `bold`, `dim`, `italic`, `underline`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `gray`, `bgRed`, `bgGreen`, etc. Color support is auto-detected.

## Agent Detection

goke exports `isAgent`, `agent`, `agentInfo`, and `detectAgent()` from `goke/src/agents.ts`. Use `isAgent` to detect if the CLI is running inside an AI coding agent and skip interactive prompts or prefer structured output.

```ts
import { isAgent, agent } from 'goke'

if (isAgent) {
  // skip clack prompts, output YAML/JSON instead of interactive UI
}
```

`isAgent` is for **skipping interactive prompts that have a CLI flag alternative** (e.g. `--env staging` instead of a clack select). Use it to require the flag and fail with a usage hint instead of hanging on stdin:

```ts
if (!env) {
  if (isAgent || !process.stdin.isTTY) {
    console.error('Missing --env. Usage: deploy --env staging|production')
    process.exit(1)
  }
  // ... clack prompt fallback
}
```

**Never use `isAgent` to block commands that have no flag alternative**, like device-flow login. Those commands don't read stdin at all; they open a browser, print a code, and poll. The only real requirement is a TTY for spinner output. Use `!process.stdin.isTTY` or `!process.stdout.isTTY` alone for those:

```ts
// login command — no flag alternative, agent can run it in tuistory
if (!process.stdin.isTTY) {
  console.error('Login requires a terminal. Run in tuistory or tmux.')
  process.exit(1)
}
```

Agents can run login commands in a PTY via tuistory and complete the browser flow with playwriter. Blocking them with `isAgent` makes login impossible from agent contexts.

Supported agents: `cursor`, `claude`, `devin`, `replit`, `gemini`, `codex`, `auggie`, `opencode`, `kiro`, `goose`, `pi`. Set `AI_AGENT` env var to override.

## Long-Running Interactive Commands

Commands that start a browser/device login flow need to work for both interactive users and AI agents. goke's built-in **daemon** pattern (`ctx.daemon`) handles this: the command forks itself into a background process that waits for browser approval, while the foreground returns immediately so agents aren't blocked.

Use `isAgent` to branch between agent mode (start daemon, return immediately) and interactive mode (block until login completes). Do not fail in non-TTY shells; use the daemon instead.

```ts
import { goke, isAgent, openInBrowser } from 'goke'

cli
  .command('login', 'Authenticate with browser login')
  .action(async (options, ctx) => {
    if (ctx.daemon.isDaemon) {
      // ── DAEMON: create the URL, hand it to the foreground, then wait ──
      const flow = await startOAuthFlow({ /* ... */ })
      ctx.daemon.publishStartupMessage(`Authorize: ${flow.authorizationUrl}`)
      ctx.daemon.ready()
      const result = await flow.waitForApproval()
      if (result.success) saveAuth(result)
      return // daemon exits, PID file is cleaned up
    }

    // ── CLIENT: decide foreground vs background ──
    if (isAgent) {
      // Agent mode: return after the daemon publishes its authorization URL
      await ctx.daemon.start({
        waitForStartup: true,
        timeoutMs: 10 * 60 * 1000,
      })
      ctx.console.log('Login running in background.')
      ctx.console.log('After approving in browser, verify with: mycli me')
      return
    }

    // Interactive mode: attach to daemon, see all its logs and errors in real time
    await ctx.daemon.start({ attach: true, timeoutMs: 10 * 60 * 1000 })
    ctx.console.log('Login successful!')
  })
```

Use `waitForStartup: true` when the daemon creates an OAuth URL, device code, or other value that the agent must see before the foreground command returns. Publish ordered messages with `publishStartupMessage(message, { stream: 'stdout' | 'stderr' })`, then call `ready()`. Detached stdio remains ignored. Attached mode still receives the messages directly and waits for the daemon to exit.

Add a `me` command (exits 0 if logged in, 1 if not) so agents can poll for completion. Use `ctx.daemon.forCommand('login')` to check the login daemon status from other commands. See the **Background Daemons** section in the goke README for the full pattern, including `env` passthrough and PID file safety.

## Shell Completions

**Always add `.completions()` next to `.help()` in every CLI.** This gives users Tab completion for free.

```ts
cli.help()
cli.completions()
cli.parse()
```

### How it works

The shell calls the CLI binary on every Tab press with a hidden `--get-goke-completions` flag. The binary inspects registered commands and options, prints matching candidates to stdout, and exits. No static completion file to regenerate when commands change.

### README section for new CLIs

Every new CLI should include a **Shell Completions** section in its README. Add it after the main usage docs:

````md
## Shell Completions

Enable Tab completion for your shell:

```bash
mycli completions install
```

Restart your shell (or run `autoload -Uz compinit && compinit` for zsh). Then Tab works:

```bash
mycli <TAB>          # shows all commands
mycli dep<TAB>       # completes to "deploy"
mycli deploy --<TAB> # shows available options
```

Completions stay up-to-date automatically. To remove:

```bash
mycli completions uninstall
```
````

Replace `mycli` with the actual CLI name.

### Available completions commands

`.completions()` registers three subcommands:

- `completions install` — finds a writable shell completion directory and writes the shim script
- `completions uninstall` — removes installed completion files
- `completions script` — prints the raw script to stdout (for `eval` or piping)

All three accept `--shell zsh` or `--shell bash` to override auto-detection.

## openInBrowser is async

`openInBrowser` returns a `Promise<void>` and **must be awaited**. Without `await`, the process may exit before the browser opens. In non-TTY environments it writes the URL to stderr, keeping stdout clean for JSON parsing.

```ts
import { openInBrowser } from 'goke'

await openInBrowser('https://example.com/dashboard')
```

## Command Descriptions and Examples

**Use backtick formatting in descriptions** for flags and command references (e.g. `` `--status` ``, `` `mycli deploy` ``). Plain text flag names won't render as code in generated docs.

**Use `.example()` for usage examples, not the description string.** `generateDocs()` auto-wraps `.example()` strings in fenced `` ```sh `` code blocks. Examples in the description render as plain text without syntax highlighting.

```ts
cli.command(
  'query <sql>',
  dedent`
    Run a SQL query. Add \`--json\` for the raw JSON envelope.
  `,
)
  .example('mycli query "SELECT * FROM users" -p my-app')
  .example('mycli query "SELECT * FROM users FORMAT CSV" > out.csv')
```

## Command Naming Conventions

**ALWAYS read existing commands before adding a new one.** Scan the CLI for option names, verbs, and noun patterns already in use. New commands must stay consistent with what exists.

### Consistent option names

Options that do the same thing across different commands must use the same name. For example, if `list` commands already use `--limit` to cap results, never introduce `--max` or `--count` for the same purpose in a new command. Grep the codebase for similar options before picking a name.

### CRUD-style spaced commands

Prefer spaced subcommands that read like `noun verb`:

```
project list
project add
project remove
```

Pick **singular or plural** for the noun and stick with it across the entire CLI. If `project list` exists, don't add `projects add`.

**Always group namespaced commands with `.section()`.** Commands that share a parent word (`get pods`, `get services`, `auth login`) must sit under a named heading in root help. Call `cli.section('Get')` before registering that group. Use `.command(...).section('Name')` when one command belongs in a different group.

```ts
cli.section('Get')
cli.command('get pods', 'List pods')
cli.command('get services', 'List services')

cli.section('Describe')
cli.command('describe pod <name>', 'Describe a pod')
```

### Consistent verbs

Choose one verb per action and reuse it everywhere:

| Action | Pick one | Not both |
|--------|----------|----------|
| Create | `add` or `create` | not both |
| Delete | `remove` or `delete` | not both |
| Show   | `show` or `get` | not both |
| Update | `update` or `edit` | not both |

Check which verbs the CLI already uses and match them. If existing commands use `add`, every new "create something" command should also use `add`.

### Never mix different ID kinds in positionals

All positionals of a command must identify the same kind of thing. Never give the first positional a different meaning than the rest (e.g. `events <recordingId> [...eventIds]`): a call like `events 1 4 7` is unreadable because the first number silently refers to a different entity. Move the parent/scoping ID to an optional flag with a sensible default and keep positionals homogeneous:

```ts
cli
  .command('recorder events [...eventIds]', 'Print recorded events')
  .option('-r, --recording <id>', 'Recording ID (defaults to the latest recording)')
```

## Prefer Optional Flags Over Required Flags

**Never make a flag required when it can be optional with an interactive fallback.** Required flags force users to read `--help` before they can run anything. Optional flags let them run the bare command and discover options progressively through prompts.

The pattern: make the flag optional, and when the user omits it, show a `clack.select` prompt in TTY mode or exit with a clear error in non-TTY mode.

```ts
cli
  .command('deploy', 'Deploy the app')
  .option(
    '--env [env]',
    z.enum(['staging', 'production']).optional().describe('Target environment'),
  )
  .action(async (options) => {
    let env = options.env

    if (!env) {
      if (!process.stdin.isTTY) {
        console.error('Missing --env. Usage: deploy --env staging|production')
        process.exit(1)
      }

      const choice = await clack.select({
        message: 'Which environment?',
        options: [
          { value: 'staging', label: 'Staging' },
          { value: 'production', label: 'Production', hint: 'requires approval' },
        ],
      })
      if (clack.isCancel(choice)) {
        process.exit(0)
      }
      env = choice
    }

    // env is now guaranteed to be defined
  })
```

This applies to every flag that has a finite set of valid values. If you can enumerate the choices, make it a select prompt. The non-TTY error message must show the exact flag name and valid values so agents and CI scripts can self-correct.

**Bad** — forces users to know the flag upfront:

```ts
.option('--env <env>', z.enum(['staging', 'production']).describe('Target environment'))
```

**Good** — users can just run `deploy` and get prompted:

```ts
.option('--env [env]', z.enum(['staging', 'production']).optional().describe('Target environment'))
```

For flags with free-form string values (not enums), use `clack.text` instead of `clack.select`:

```ts
if (!options.name) {
  if (!process.stdin.isTTY) {
    console.error('Missing --name. Usage: create --name "my-project"')
    process.exit(1)
  }

  const name = await clack.text({ message: 'Project name' })
  if (clack.isCancel(name)) process.exit(0)
  options.name = name
}
```

## Error Messages with Recovery Hints

**Every error message should include a hint showing how to fix or rerun the command.** When a CLI exits with an error, the user (or agent) should be able to copy-paste a corrected command immediately instead of reading `--help`.

```ts
console.error('Failed to detect local port.')
console.error('If your server prints the port in an unusual format, specify it explicitly:')
console.error(`  mycli serve -p <port> -- ${shellQuote(args)}`)
process.exit(1)
```

Include the user's original arguments in the suggested command when possible, so the hint is directly copy-pasteable. For timeouts, show how long it waited so the user knows whether to wait longer or try a different approach.

## Interactive Prompts with @clack/prompts

Use `@clack/prompts` for interactive CLI prompts like `select`, `confirm`, and text input.

```bash
npm install @clack/prompts
```

```ts
import * as clack from '@clack/prompts'

const method = await clack.select({
  message: 'Choose authentication method',
  options: [
    { value: 'google', label: 'Google', hint: 'opens browser for OAuth' },
    { value: 'imap', label: 'Other', hint: 'IMAP/SMTP with password' },
  ],
})
if (clack.isCancel(method)) {
  process.exit(0)
}

const confirmed = await clack.confirm({
  message: 'Delete this item?',
  initialValue: false,
})
if (clack.isCancel(confirmed) || !confirmed) {
  process.exit(0)
}
```

Always guard clack prompts with `process.stdin.isTTY`. Agents and CI often run with non-TTY stdin, so interactive prompts must fall back to explicit CLI options instead of hanging.

### Select prompts

When a command shows a `select` prompt in TTY mode, always add a matching CLI option so agents can pass the choice directly.

```ts
cli
  .command('login', 'Authenticate')
  .option(
    '--method <method>',
    z.enum(['google', 'imap']).optional().describe('Authentication method'),
  )
  .action(async (options) => {
    let method = options.method

    if (!method) {
      if (!process.stdin.isTTY) {
        console.error('Run non-interactively with: zele login --method google|imap')
        process.exit(1)
      }

      const choice = await clack.select({
        message: 'Choose authentication method',
        options: [
          { value: 'google', label: 'Google', hint: 'opens browser for OAuth' },
          { value: 'imap', label: 'Other', hint: 'IMAP/SMTP with password' },
        ],
      })
      if (clack.isCancel(choice)) {
        process.exit(0)
      }
      method = choice
    }

    if (method === 'imap') {
      return
    }
  })
```

### Confirm prompts

For destructive confirmations, add a `--force` flag and exit with a clear error in non-TTY mode when it is missing.

```ts
cli
  .command('delete <id>', 'Delete an item')
  .option('--force', 'Skip confirmation')
  .action(async (id, options) => {
    if (!options.force) {
      if (!process.stdin.isTTY) {
        console.error('Use --force to delete non-interactively')
        process.exit(1)
      }

      const confirmed = await clack.confirm({
        message: `Delete ${id}?`,
        initialValue: false,
      })
      if (clack.isCancel(confirmed) || !confirmed) {
        return
      }
    }
  })
```

## Remote Server Auth & Config

CLIs that talk to a remote server must support multiple server URLs so users can self-host, use a preview/staging environment, or point to localhost during development. Auth tokens and other per-server state live in a JSON config file keyed by API URL.

**Never log config file paths** (like `~/.myapp/config.json` or `~/.myapp/auth.json`) in CLI output. Agents read CLI output and will try to `cat` or parse these files directly, bypassing the CLI's own commands. Log success/failure messages without revealing internal storage paths.

### Config file location

Store config at `~/.cliname/config.json`. The directory is named after the CLI binary. Use `os.homedir()` to resolve `~`.

### Config structure

The config is an object keyed by server URL. Each entry holds auth tokens and any other per-server state. The CLI reads/writes only the entry matching the current `--api-url`.

```ts
// ~/.cliname/config.json
{
  "https://api.cliname.com": {
    "accessToken": "tok_abc123",
    "refreshToken": "rt_xyz789",
    "expiresAt": "2026-08-01T00:00:00Z"
  },
  "https://staging.cliname.com": {
    "accessToken": "tok_staging_456"
  },
  "http://localhost:3000": {
    "accessToken": "tok_dev_789"
  }
}
```

### Global `--api-url` option

Register `--api-url` as a global option with a default pointing to the production hosted service. The `.use()` middleware resolves the final URL from the flag, env var, or default, then **writes it back to `process.env`**. All other code just reads `process.env.CLINAME_API_URL` instead of threading `options.apiUrl` through every function call. This avoids type-safety issues since global options aren't visible in command action types.

```ts
import { goke } from 'goke'
import { z } from 'zod'

const DEFAULT_API_URL = 'https://api.cliname.com'

const cli = goke('cliname')

cli.option(
  '--api-url [url]',
  z.string().url().optional().describe('Server URL'),
)

cli.use((options) => {
  const apiUrl = (
    options.apiUrl
    || process.env.CLINAME_API_URL
    || DEFAULT_API_URL
  ).replace(/\/+$/, '') // normalize: strip trailing slash so config keys are consistent

  process.env.CLINAME_API_URL = apiUrl
})
```

After this middleware runs, any module can call `getApiUrl()` without receiving it as a parameter:

```ts
export function getApiUrl(): string {
  return process.env.CLINAME_API_URL!
}
```

### Reading and writing config

Config helpers take the injected `fs` from the action context as an object argument. This keeps them portable across normal Node.js runs and JustBash sandboxes.

```ts
import path from 'node:path'
import os from 'node:os'
import type { GokeFs } from 'goke'

const CONFIG_DIR = path.join(os.homedir(), '.cliname')
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json')

interface ServerConfig {
  accessToken?: string
  refreshToken?: string
  expiresAt?: string
}

type Config = Record<string, ServerConfig>

async function loadConfig({ fs }: { fs: GokeFs }): Promise<Config> {
  try {
    return JSON.parse(await fs.readFile(CONFIG_PATH, 'utf-8'))
  } catch {
    return {}
  }
}

async function saveConfig({ fs, config }: { fs: GokeFs; config: Config }) {
  await fs.mkdir(CONFIG_DIR, { recursive: true })
  await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n')
}

async function getServerConfig({ fs }: { fs: GokeFs }): Promise<ServerConfig> {
  const config = await loadConfig({ fs })
  return config[getApiUrl()] ?? {}
}

async function setServerConfig({ fs, data }: { fs: GokeFs; data: ServerConfig }) {
  const apiUrl = getApiUrl()
  const config = await loadConfig({ fs })
  config[apiUrl] = { ...config[apiUrl], ...data }
  await saveConfig({ fs, config })
}
```

### Using it in commands

Commands pass the injected `{ fs }` to config helpers and read the API URL via `getApiUrl()`.

```ts
cli
  .command('login', 'Authenticate with the server')
  .action(async (_options, { fs, console }) => {
    const apiUrl = getApiUrl()
    const token = await doLogin(apiUrl)
    await setServerConfig({ fs, data: { accessToken: token } })
    console.log(`Logged in to ${apiUrl}`)
  })

cli
  .command('status', 'Show current config')
  .action(async (_options, { fs, console }) => {
    const apiUrl = getApiUrl()
    const server = await getServerConfig({ fs })
    console.log(`Server: ${apiUrl}`)
    console.log(`Authenticated: ${server.accessToken ? 'yes' : 'no'}`)
  })

cli
  .command('logout', 'Clear auth for current server')
  .action(async (_options, { fs, console }) => {
    const apiUrl = getApiUrl()
    const config = await loadConfig({ fs })
    delete config[apiUrl]
    await saveConfig({ fs, config })
    console.log(`Logged out from ${apiUrl}`)
  })
```

### Why key by URL

- Users can be logged in to production and staging simultaneously
- Self-hosters get isolated auth without conflicting with the hosted service
- Developers can point to `http://localhost:3000` during development without losing their production token
- Switching servers is just `--api-url` or setting an env var; no re-login needed if the server was used before
```

## MCP CLIs (`@goke/mcp`)

Use `addMcpCommands` from `@goke/mcp`. Do not hide `--help` behind a token. Put token steps on a `config` command. Never write `isSetupCmd` or a first-run prompt that blocks no-args.

Use `getMcpUrl` plus `getHeaders` for HTTP Bearer tokens. Use `getMcpTransport` for stdio or any custom transport.

```ts
await addMcpCommands({
  cli,
  getMcpUrl: () => MCP_URL,
  getHeaders: () => {
    const token = process.env.TOKEN || loadConfig().token
    if (!token) return
    return { Authorization: `Bearer ${token}` }
  },
  loadCache: () => loadConfig().cache,
  saveCache: (cache) => saveConfig({ cache }),
})
```

## Writing a Skill for a goke CLI

When creating a SKILL.md for a CLI built with goke, keep it **thin**. The skill is a bridge between the agent and the canonical docs, not a copy of them.

### Structure

1. **Always start with `--help`.** The CLI self-documents commands, options, and examples via goke's help generator. Make agents read it first, in full, every session. Add a "Read the help first" section with `mycli --help` and a rule to never truncate with `head`, `tail`, or `sed -n`.

2. **Point at canonical docs.** If the CLI has a docs site with `llms-full.txt` (e.g. built with Holocron), tell agents to `curl -s https://mycli.dev/llms-full.txt` as the single source of truth. For OSS repos without a docs site, curl the raw README from GitHub: `curl -s https://raw.githubusercontent.com/owner/repo/main/README.md`. Add a "never truncate" rule next to the curl command. Optionally list 3-4 individual page URLs for the most common quick lookups.

3. **Install and auth.** Just the commands, one per line, minimal prose. Start with `which mycli` so agents check before installing. Then `npm install -g mycli`, `mycli auth check`, `mycli auth login`, and `mycli auth set --key` for CI.

4. **Gotchas.** Agent-specific knowledge that is not obvious from `--help` or the docs. Things like browser flows that need user interaction, remote vs local file path restrictions, implicit defaults that cause silent failures, and subscription requirements.

5. **MCP alternative.** If the CLI has an MCP server, include the one-liner install command.

### What NOT to put in the skill

- **Command reference** — already in `--help` output
- **Workflow examples** — belong in the docs site (quickstart, guides)
- **Option descriptions** — already in Zod `.describe()` strings that goke renders in help
- **Output format details** — covered by `--help` and docs

If a section in the skill duplicates content from `--help` or the docs, delete it. The agent will fetch the canonical source.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.