StableAdapters

Claude Code Adapter

The Claude Code adapter uses Claude Code's built-in hooks API to emit signals after every tool invocation. It captures all 7 hook event types: PostToolUse, PreToolUse, SessionStart, SessionEnd, Stop, PreCompact, and UserPromptSubmit.

Prerequisites

  • Claude Code installed and configured
  • FORG CLI installed and activated (forg status shows your device)
  • Claude Code version 1.2.0 or later (hooks API required)

Installation

Run forg connect claude-code to install automatically, or add the following to ~/.claude/settings.json (or a project-level .claude/settings.json):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event PostToolUse" }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event PreToolUse" }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event SessionStart" }
        ]
      }
    ],
    "SessionEnd": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event SessionEnd" }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event Stop" }
        ]
      }
    ],
    "PreCompact": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event PreCompact" }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "matcher": ".*",
        "hooks": [
          { "type": "command", "command": "forg emit --event UserPromptSubmit" }
        ]
      }
    ]
  }
}

When Claude Code fires a hook, it pipes a JSON context to stdin. The forg emit command auto-detects piped stdin (no --stdin flag needed) and reads the hook context automatically.

How it works

Claude Code fires the PostToolUse hook after each tool call and passes a JSON context to stdin with fields including:

{
  "tool_name":   "Bash",
  "model":       "claude-opus-4-5",
  "usage": {
    "input_tokens":  1024,
    "output_tokens": 512,
    "cache_read_input_tokens": 256
  },
  "cost_usd":    0.0042,
  "session_id":  "..."
}

The FORG agent reads this context, normalizes it to the FORG signal schema, and POSTs it directly to https://engine.forg.pro/signalsigned with the device's HMAC session key.

HMAC session key

Each FORG session has an HMAC session key derived from the device bundle. The engine sets FORG_SESSION_KEY and FORG_SESSION_ID in the hook environment so every forg emit invocation can sign its signal correctly. This prevents spoofed signals from other processes on the same machine.

Verification

# Check that a session is active and adapters are installed:
forg status

# Expected output:
# user_id:        usr_...
# device:         a3f9e2c1b84d...
# engine:         https://engine.forg.pro
# license worker: https://api.forg.pro
#
# session:        a3f9e2c1 (active)
#
# Installed adapters:
#   ✓ Claude Code (free)

Project-level config

To enable FORG only in specific projects, add the hooks config to .claude/settings.json in the project root instead of the global settings. This is useful when you want to track a specific repository separately.

Status bar integration

FORG writes a ~/.claude/statusline.sh script during activation that shows live session metrics in the Claude Code status bar. If you already have a custom statusline.sh, FORG will not overwrite it — a warning is surfaced at activation time instead.

You can also use forg status --inline to get a one-line status string suitable for use in your own status bar script:

forg status --inline
# FORG · a3f9e2c1 · 2 tools

Troubleshooting

SymptomFix
No signals appearing after tool callsVerify ~/.claude/settings.json is valid JSON with correct hook commands. Run forg status to confirm a session is active.
Hook fires but signals are rejected (401)HMAC mismatch. Ensure FORG_SESSION_KEY and FORG_SESSION_ID are set in the hook environment by Claude Code.
High latency on tool callsThe hook runs synchronously before the tool result is returned. The emit timeout is 3s. Check network connectivity to engine.forg.pro.
Claude Code shows statusline errorIf you have a custom statusline.sh, FORG's status indicator won't overwrite it. This is expected behavior.

Known limitations

  • Cost data accuracy depends on Claude Code's reported cost; FORG does not independently price model calls
  • Cache token counts (cache_read, cache_write) are tracked separately and included in tokens_in
  • SubAgent tool calls inside a session are attributed to the same session_id
© 2026 UpgradIQ, Inc.Edit this page on GitHub