<!--
SPDX-FileCopyrightText: Amolith <amolith@secluded.site>

SPDX-License-Identifier: Unlicense
-->

# synu

Universal wrapper for LLM agents that tracks
[Synthetic](https://synthetic.new) usage and interactively preconfigures
supported agents for currently-available models (so you can try a new
one as soon as they support it, without waiting for the agent itself to
gain support!)

## Requirements

- Fish
- `curl` - for API requests
- `jq` - for JSON parsing
- `gum` - for interactive model selection
  ([install](https://github.com/charmbracelet/gum))
- `SYNTHETIC_API_KEY` environment variable (for quota tracking with
  Synthetic)

## Installation

### Using Fundle

Add to your `~/.config/fish/config.fish`:

```fish
fundle plugin 'synu' --url 'https://git.secluded.site/synu'
fundle init
```

Then reload your shell or run `fundle install`.

## Configuration

Set your Synthetic API key in your `~/.config/fish/config.fish`:

```fish
# For Synthetic API quota tracking
set -gx SYNTHETIC_API_KEY your_api_key_here
```

## Usage

Use `synu` as a wrapper for any AI agent:

```fish
# Check current quota
synu

# Use with configured agents (auto-routed through Synthetic)
synu claude "What does functions/synu.fish do?"
synu opencode "Help me refactor this"
synu aider "Fix the bug in main.go"

# Use with other agents (passthrough with quota tracking)
synu crush "Help me write code"

# Any other agent or command
synu [agent-name] [agent-args...]
```

> **Note**: synu's configuration is ephemeral and non-invasive. Running
> `synu claude` routes requests through Synthetic, but running `claude`
> directly still uses Anthropic's API with your normal configuration.
> synu never modifies the agent's own config files.

### Interactive Model Selection

Use `synu i <agent>` to fetch the list of available models and
interactively filter/select them using gum:

```fish
synu i claude "prompt"
synu i opencode "prompt"
synu i aider "prompt"
```

You'll be asked whether to save your selection as the default for future
sessions.

### Persistent Preferences

Model selections made in interactive mode can be saved to
`~/.config/synu/models.conf`. These become the new defaults until
changed. Command-line flags always override saved preferences.

## Configured Agents

### Claude Code

| Tier | Default Model |
|------|---------------|
| Opus | `hf:moonshotai/Kimi-K2-Thinking` |
| Sonnet | `hf:zai-org/GLM-4.6` |
| Haiku | `hf:deepseek-ai/DeepSeek-V3.1-Terminus` |
| Subagent | `hf:zai-org/GLM-4.6` |

**Override flags:**

```fish
# Override specific models
synu claude --opus hf:other/model "prompt"
synu claude --sonnet hf:other/model "prompt"
synu claude --haiku hf:other/model "prompt"
synu claude --agent hf:other/model "prompt"

# Group overrides
synu claude --large hf:model "prompt"  # Sets Opus, Sonnet, and Subagent
synu claude --light hf:model "prompt"  # Sets Haiku
```

### OpenCode

| Default Model |
|---------------|
| `hf:zai-org/GLM-4.6` |

```fish
synu opencode --model hf:other/model "prompt"
```

### Aider

| Slot | Default Model |
|------|---------------|
| Main | `hf:zai-org/GLM-4.6` |
| Editor | `hf:deepseek-ai/DeepSeek-V3.1-Terminus` |

```fish
# Single model mode
synu aider --model hf:some/model "prompt"

# Architect + editor mode (two models)
synu aider --model hf:architect/model --editor-model hf:editor/model "prompt"
```

### llxprt

| Default Model |
|---------------|
| `hf:zai-org/GLM-4.6` |

```fish
synu llxprt --model hf:other/model "prompt"
```

### Qwen Code

| Default Model |
|---------------|
| `hf:zai-org/GLM-4.6` |

```fish
synu qwen --model hf:other/model "prompt"
```

## How it works

`synu` works by:

1. Loading agent-specific configuration if available
2. Fetching initial quota from the Synthetic API before running the
   agent
3. Configuring the agent's environment/CLI args to route through
   Synthetic
4. Executing the specified agent with all provided arguments
5. Cleaning up environment variables after execution
6. Fetching final quota and displaying session usage

The quota tracking requires the `SYNTHETIC_API_KEY` environment
variable. Without it, `synu` will show a warning and skip quota
tracking, but still attempt to run the agent.

## Shell completions

Synu includes fish shell completions for configured agents and their flags.

## Contributions

Patch requests are in [amolith/llm-projects] on [pr.pico.sh]. You don't need a
new account to contribute, you don't need to fork this repo, you don't need to
fiddle with `git send-email`, you don't need to faff with your email client to
get `git request-pull` working...

You just need:

- Git
- SSH
- An SSH key

```sh
# Clone this repo, make your changes, and commit them
# Create a new patch request with
git format-patch origin/main --stdout | ssh pr.pico.sh pr create amolith/llm-projects
# After potential feedback, submit a revision to an existing patch request with
git format-patch origin/main --stdout | ssh pr.pico.sh pr add {prID}
# List patch requests
ssh pr.pico.sh pr ls amolith/llm-projects
```

See "How do Patch Requests work?" on [pr.pico.sh]'s home page for a more
complete example workflow.

[amolith/llm-projects]: https://pr.pico.sh/r/amolith/llm-projects
[pr.pico.sh]: https://pr.pico.sh
