v0.1 · open source · MIT

The ferryman.
Your agents don't carry the toll.

Charon sits between your agents and the internet. Agents make requests as themselves — no credentials in their context, no API keys in their prompts. Charon holds the secrets, looks up the right one per its policy, injects it at proxy-time, audit-logs the call. Your credentials never enter an LLM context window.

What Charon does

Four primitives, one HTTP endpoint, zero credentials in your agent's prompt.

Encrypted credential vault

AES-256-GCM at rest, Argon2id key derivation, never in agent context. Swap the local backend for AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager via one interface.

Declarative policy DSL

Tiny YAML file binds host_pattern + skill to a credential injection. Bearer tokens, custom headers, query params, basic auth — all supported. First-match-wins.

OAuth2 refresh-token exchange

Long-lived refresh tokens stay in the vault. Charon exchanges for short-lived access tokens just in time, caches per-credential, refreshes before expiry. The agent never sees either token.

Append-only audit log

Every credentialed call is one JSON line: skill, host, status, latency, matched rule. When the surprise API charge shows up Tuesday, you can correlate it to "which agent, which skill, which tool call".

Scoped by skill identity

Each request carries a skill identifier; policy rules can scope by skill. A compromised "search" skill can't suddenly call your billing API just because the credentials are nearby.

HTTP-only wire protocol

One endpoint: POST /proxy. Three headers, body forwarded. No SDK required — if your stack can curl, your stack can use Charon. Tiny Go SDK for tight integrations.

Declare which credential goes where.

A tiny YAML file is the whole configuration surface. First-match-wins; order specific rules above generic ones.

~/.charon/charon.yaml
# Bind a host + skill to a credential injection
rules:
  # Gmail OAuth2 refresh-token flow
  - name: gmail-oauth
    when:
      host_pattern: "*.googleapis.com"
      skill: gmail
    inject:
      type: bearer
      secret: GMAIL_ACCESS_TOKEN
      refresh:
        type: oauth2
        token_url: https://oauth2.googleapis.com/token
        refresh_token_secret: GMAIL_REFRESH_TOKEN
        # ... + client_id / client_secret

  # Static bearer for the Slack API
  - name: slack-api
    when:
      host_pattern: "slack.com"
      skill: slack
    inject:
      type: bearer
      secret: SLACK_BOT_TOKEN

Stop putting API keys in your agent's prompt.

Open source. MIT-licensed. Built to bolt on, not lock in.