AGENTS.md

AGENTS.md

Project Overview

synclaude.fish is a Fish shell wrapper for the claude CLI that routes requests through Synthetic.new's API. It enables using alternative AI models (like GLM-4.6, Llama, Qwen) through the Claude CLI by proxying requests through Synthetic's Anthropic-compatible endpoint.

Key Functionality

  • Defaults all Claude model tiers (Opus, Sonnet, Haiku, Sub-agent) to hf:zai-org/GLM-4.6
  • Provides interactive TUI for model selection using gum
  • Supports group-based (--large/--light) and individual model overrides
  • Displays session API usage and remaining quota after each run
  • Wraps claude CLI completely - all unknown flags pass through

Project Structure

This is a standard Fish plugin with the following structure:

synclaude.fish/
├── README.md              # User documentation
├── functions/
│   └── synclaude.fish     # Main wrapper function (~156 lines)
└── completions/
    └── synclaude.fish     # Tab completions (~15 lines)

Architecture

Control Flow:

  1. Interactive mode (synclaude i):
  • Fetches available models from Synthetic API
  • Prompts user to choose Groups vs Individual models
  • Prompts for which groups/models to override
  • For each selection, filters available models with gum filter
  • Recursively calls synclaude with generated flags (lines 83-84)
  1. Flag-based mode (default):
  • Parses custom flags with argparse --ignore-unknown (lines 91-94)
  • Sets environment variables for Anthropic endpoint and model overrides
  • Fetches initial quota from Synthetic API
  • Executes command claude $argv (line 128)
  • Fetches final quota and displays usage stats with color-coding

Key Design Patterns:

  • Override precedence: Individual flags override group flags, which override defaults (lines 107-121)
  • Error propagation: Uses or return throughout to exit on command failures

Code Conventions

Fish Shell Patterns

  • Local variables: Always use set -l for function-local scope
  • Export variables: Use set -lx for locally-scoped exports (lines 96-104)
  • Variable checking: Use set -q variable to test existence (lines 107-121)
  • Array removal: Use set -e argv[1] to remove elements (line 6)
  • Command substitution: Use (command) not backticks
  • Error handling: Chain commands with or return for early exits
  • Math operations: Use math builtin with -s0 for integer results (line 139)

Code Style

  • Indentation: 4 spaces (not tabs)
  • Line length: No hard limit, but keep logical blocks readable
  • Variable naming:
    • Descriptive names: models_json, initial_requests, quota_color
    • No abbreviations except common ones: argsargv, argargv
  • Comments:
    • Group logic blocks with descriptive comments (lines 88-90)
    • Inline comments for non-obvious conditions (lines 125, 132)
    • No redundant comments explaining obvious code

API Interaction Patterns

All API calls wrapped in gum spin for UX:

set -l response (gum spin --spinner dot --title "Message..." -- curl -s -H "Authorization: Bearer $KEY" https://api.url)

API responses always:

  1. Use jq -r for raw (unquoted) output
  2. Provide fallback values with // 0 or similar (lines 125, 132-133)
  3. Test for empty values after extraction (line 126)
  4. Redirect stderr to /dev/null if errors are expected (lines 124, 131)

Error Handling

  • API failures: Use or return 1 to exit on curl/jq errors
  • Null safety: Always test extracted values before use (line 126)
  • Propagate exit codes: Return $status from wrapped command (line 84)
  • Silent failures: Only suppress stderr when errors are expected and handled

Completions

File: completions/synclaude.fish

  • Inherits from wrapped command: complete -c synclaude -w claude (line 2)
  • Subcommand prevention: Use -n "not __fish_seen_subcommand_from i" to prevent completions after i (line 5)
  • Flag completions: -s (short), -l (long), -r (requires argument), -d (description)

Quota Display Logic

Post-execution, displays:

  • Session usage: final_requests - initial_requests
  • Remaining quota: limit - final_requests (color-coded)

Color coding (lines 141-146):

  • Green: <33% used
  • Yellow: 33-66% used
  • Red: >66% used

Color logic uses set_color and set_color normal to wrap output (lines 151-153).

Common Gotchas

  1. argparse --ignore-unknown is critical: Without it, unknown flags would error instead of passing through to claude (line 91)
  2. Recursive call must use function name, not alias: Line 83 calls synclaude, not command synclaude - this works because Fish functions can recursively invoke themselves
  3. _flag_* variable naming: argparse creates variables from flag names with _flag_ prefix - must use exact names (lines 107-121)
  4. Model ID vs Model Name: Interactive mode fetches model names for display but must extract model IDs for API use (lines 30, 37, 53, 60, 67, 74)
  5. jq requires argument quoting: In jq, use --arg name "$var" then $name in filter - don't interpolate directly into filter string
  6. Quota check timing: Initial quota fetch happens before claude runs to calculate session usage. If it fails, script continues anyway
  7. math precision: Use -s0 for integer output to avoid decimal points in quota percentages
  8. Local exports don't persist: set -lx variables only exist in function scope - won't affect parent shell