SigCLI

SkillWeb & browsing

Guide Claude to use SigCLI correctly — check auth, login, get credentials, configure providers, and onboard new websites. Trigger when using sig commands, editing ~/.sig/config.yaml, or needing authenticated API access.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the SigCLI skill

What this skill tells your AI

The instructions your AI receives, as published by sigcli/sigcli in skills/sigcli/SKILL.md and read by ahel’s review.

Reference for using SigCLI correctly. Prevents common mistakes like inventing flags, using redacted output, or misconfiguring providers.

Constraints

These are the most common mistakes. Read them FIRST.

  1. sig get MUST use --no-redaction to get usable values. Without it, output is ****. This is the #1 mistake.
  2. Never invent commands. The ONLY commands are: init, doctor, login, logout, get, request, status, providers, rename, remove, remote, sync, watch, proxy, run, completion.
  3. Never invent flags. See Command Reference below for exact flags per command.
  4. Never invent config fields. There is NO requiredCookies, loginUrl, cookies, headers, authUrl, token, credentials, or session field. See Provider Config Schema for the exact list.
  5. sig login two forms:
    • sig login <provider> — provider already configured in config.yaml
    • sig login https://example.com — auto-provision (creates provider automatically). Use --as for a meaningful name: sig login https://example.com --as example
  6. sig run output is redacted. It injects SIG_<PROVIDER>_<KEY> env vars into the child process, but redacts them in stdout. Use env | grep SIG_ inside the child to discover var names.
  7. sig get --format only accepts: json, header, value. Not cookie-jar, env, raw, etc.
  8. Provider config extract and apply are ARRAYS (list of objects), not single objects.
  9. Don't modify existing provider configs unless explicitly asked by the user.

Command Reference

CommandUsageKey Flags
initsig init--remote, --yes, --force
doctorsig doctor
loginsig login <provider>--as <id>, --strategy oauth2, --token-url, --client-id, --client-secret, --scope, --mode auto|headless|visible, --network-proxy
logoutsig logout [provider]
getsig get <provider>--format json|header|value, --no-redaction
requestsig request <url>--method, --body, --header "K: V", --format json|body|headers
statussig status [provider]--format json|yaml|table|plain
providerssig providers--format json|yaml|table|plain
renamesig rename <old> <new>
removesig remove <provider>--keep-config, --force
remotesig remote add|remove|listadd: <name> <host> --user, --path, --ssh-key
syncsig sync push|pull [remote]--provider, --force
watchsig watch add|remove|set-intervaladd: <provider> --auto-sync
proxysig proxy start|stop|status|truststart: --port
runsig run [providers...] -- <cmd>--expand-cookies, --mount <path>, --mount-format env|json
completionsig completion <shell>bash, zsh, fish

Global: --verbose, --help

Common Patterns

Check if auth is valid

sig status <provider>
# Look for "valid": true in JSON output

Get credentials for use

# JSON with headers (most common)
sig get <provider> --no-redaction

# Just the cookie/token string
sig get <provider> --no-redaction --format value

# Inject into another command
sig run <provider> -- <command>

Login when expired

sig login <provider>                 # auto mode (headless first, then visible)
sig login <provider> --mode visible  # force open browser — USE THIS for first-time public site login

Note: sig login reuses existing valid credentials if available — it only re-authenticates when credentials are expired or missing.

Make an authenticated request

sig request https://api.example.com/endpoint --method GET

Onboarding a New Provider

When the user wants to authenticate to a new website, follow these steps:

Step 1: Try auto-provision first

sig login https://example.com --as my-site

This auto-provisions a basic config (domains, entryUrl, extract all cookies, apply as Cookie header).

If it works (you get a chance to log in, sig status my-site shows valid: true) → done.

If the browser closes immediately without letting you log in — this happens on public sites (Weibo, Reddit, X, Bilibili) where the homepage returns 200 without auth. sigcli thinks it's already authenticated because there's no redirect.

Fix: Add a validateUrl to the auto-provisioned config. Don't rewrite the config — just add the one field:

# Check what was auto-provisioned
grep -A15 "my-site:" ~/.sig/config.yaml

Edit ~/.sig/config.yaml and add a validateUrl under the provider — a URL that redirects or returns 401 when not logged in:

  my-site:
    domains:
      - example.com
    entryUrl: https://example.com/
    validateUrl: https://example.com/notifications  # ADD THIS
    strategy: browser
    ...

Then login again:

sig login my-site

Now sigcli keeps the browser open until validateUrl confirms you're authenticated.

Verify after login:

sig status my-site              # should show valid: true
sig request <validateUrl>       # should return authenticated response (not redirect/401)

Step 2: Figure out validateUrl or validateRule

validateUrl — an endpoint that returns non-2xx (or redirects) when NOT logged in:

  • Check if the site has /api/me, /api/user, /notifications, /rest/auth/1/session
  • The URL must return 2xx ONLY when authenticated
validateUrl: https://example.com/api/me

validateRule — when the endpoint always returns 200 but body differs:

  • Use a JS expression that evaluates to truthy when authenticated
  • Available variables in the sandbox:
    • res.status — HTTP status code (number)
    • res.body — parsed JSON (if response is valid JSON) or raw string
    • res.headers — object (e.g. { location: "..." })
  • The expression is wrapped in (...) and evaluated — must return truthy for "authenticated"
  • Common pitfall: res.body && res.body.name fails because empty objects {} are truthy. Be specific about what field proves authentication.
validateUrl: https://example.com/api/me
validateRule: 'res.body.name !== undefined'

More examples:

# Douyin: API returns {status_code: 0} when authenticated
validateRule: "res.body.status_code === 0"

# Site returns {logged_in: true/false}
validateRule: "res.body.logged_in === true"

# Reddit /api/me.json: returns {} when not logged in, {name: "user"} when logged in
validateRule: "typeof res.body.name === 'string'"

How to discover validateUrl and validateRule:

Prerequisites: You should know at least one authenticated API endpoint of the target site (e.g. from docs, DevTools network tab, or common patterns).

Step 1: Login first (auto-provision handles basics)

sig login https://new-website.com --as new-site

Step 2: Verify with a known API

sig request https://new-website.com/my/api

If this works (returns authenticated data), you have a good validateUrl candidate. Add it to the config.

Step 3: If sig request fails, find a suitable validateUrl

A good validateUrl must be:

  • GET method (validation only does GET)
  • Callable with just the apply rules — sigcli builds the request using your extract + apply config. If the API needs headers beyond Cookie (e.g. CSRF token), those must be in your extract/apply rules too.
  • Distinguishes authenticated from unauthenticated — the validation logic is:

How sigcli decides "authenticated" (in order):

  1. If validateRule exists → evaluate it (overrides everything below)
  2. Status 401/403/406/429 → invalid
  3. Status 3xx (redirect):
    • With explicit validateUrlany redirect = invalid (strict)
    • Without validateUrl (entryUrl fallback) → only invalid if redirect goes to /login, /signin, /auth, /sso
  4. Body < 4KB with JS redirect (window.location=, <meta http-equiv="refresh">) → invalid
  5. Otherwise → valid

Best validateUrl candidates (in order of preference):

  1. A page that redirects to login when unauthenticated — e.g. /notifications, /settings, /account, /prefs/friends. This is the cleanest: any 3xx = invalid.
  2. An API that returns 401/403 when unauthenticated — e.g. /api/me, /api/v4/me, /voyager/api/me.
  3. An API that returns 200 always but different body — needs validateRule (last resort).

Common patterns that work as validateUrl:

PatternWhy it works
/notificationsRedirects to login without auth (V2EX, Xiaohongshu)
/account, /settings, /prefs/friendsRedirects to login without auth (YouTube, Reddit)
/api/me, /api/v4/me, /voyager/api/meReturns 401 without auth (Zhihu, LinkedIn)
/i/api/2/notifications/all.jsonReturns 401/403 without auth (X — but needs csrf header)

If the API needs extra headers (e.g. CSRF token), extract them:

extract:
    - from: cookies
      as: cookie
      match: '*'
    - from: cookies
      as: csrf_token
      match: 'csrf_token_cookie_name'
apply:
    - in: header
      name: Cookie
      value: '${cookie}'
    - in: header
      name: x-csrf-token
      value: '${csrf_token}'

Some APIs need a hardcoded app-level token (e.g. X's public Bearer token):

apply:
    - in: header
      name: authorization
      value: 'Bearer AAAAAA...' # hardcoded public app token

Step 4: If validateUrl always returns 200 (rare), add validateRule

This only happens when the endpoint returns 200 for both authenticated and unauthenticated but with different body content. Compare:

# With auth
sig request https://new-website.com/api/check

# Without auth (raw curl)
curl https://new-website.com/api/check

Write a rule based on the difference. The rule sandbox has:

  • res.status — HTTP status (number)
  • res.body — auto-parsed JSON if valid, otherwise raw string
  • res.headers — response headers object
# Douyin: returns {status_code: 0} when authenticated, {status_code: -1} otherwise
validateRule: "res.body.status_code === 0"

# Reddit /api/me.json: returns {} when not logged in, {name: "user"} when logged in
validateRule: "typeof res.body.name === 'string'"

Common pitfall: res.body && res.body.name — empty objects {} are truthy! Always check a specific field value.

Step 3: Handle special extraction

Extract specific cookies (when you need individual values):

extract:
    - from: cookies
      as: cookie
      match: '*' # full cookie string
    - from: cookies
      as: csrf_token
      match: 'csrf_token' # single cookie by name

Extract from localStorage (for SPA tokens):

extract:
    - from: localStorage
      as: access_token
      match: 'auth_key_pattern'
      jsonPath: token # if the value is JSON, extract a field

Step 4: Test

sig login my-provider          # opens browser, log in
sig status my-provider         # should show valid: true
sig get my-provider --no-redaction  # should show actual credentials

If sig status shows valid: false after login:

  • The validateUrl is wrong (try a different endpoint)
  • Or add validateRule if the endpoint returns 200 regardless

Debug with: sig login my-provider --mode visible --verbose

Provider Config Schema

Valid top-level fields for a provider

my-provider:
    name: 'Display Name' # optional
    domains: [example.com] # required: list of domains
    entryUrl: https://example.com/ # required for browser/prompt; optional for oauth2
    strategy: browser # required: browser | prompt | oauth2
    ttl: 2h # optional: credential lifetime
    validateUrl: https://... # optional: URL to check auth (must 401/403 when unauthenticated)
    validateRule: 'res.body.ok' # optional: JS expression when validateUrl returns 200 regardless
    networkProxy: socks5://... # optional: proxy for this provider
    loginMode: visible # optional: auto | headless | visible
    loginUrlPatterns: [/login, /auth] # optional: URL substrings to detect login pages
    extract: [...] # required for browser/prompt: what to capture
    apply: [...] # required: how to use captured values
    oauth2: # only for strategy: oauth2
        tokenUrl: https://...
        scopes: ['scope1', 'scope2']

Note: headlessTimeout and visibleTimeout are browser-level settings (under browser: in config root), NOT provider-level.

Fields that DO NOT EXIST (never use these)

required, cookiePaths, requiredCookies, cookies, headers, loginUrl, authUrl, token, credentials, session, headlessTimeout, visibleTimeout, waitUntil

Troubleshooting

SymptomCauseFix
sig get returns ****Missing --no-redactionAdd --no-redaction flag
valid: false after loginWrong/missing validateUrlFind an API endpoint that 401s without auth
configured: falseProvider not in config.yamlAdd provider config first, then login
Browser opens but login failsSite needs visible modeUse --mode visible
sig run env vars emptyProvider credentials expiredRun sig login <provider> first
command not found: sigNot installed globallynpm install -g @sigcli/cli

Self-Test

# 1. sig is installed
sig --help 2>&1 | head -1
# Expected: "sig — authenticate once, use everywhere"

# 2. Config exists
cat ~/.sig/config.yaml | head -3
# Expected: "version: 2" or similar

# 3. Check a provider status
sig status 2>&1 | head -5

Signals

GitHub stars
290
Forks
24
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
sigcli
Source
github.com/sigcli/sigcli