Skip to content

Latest commit

 

History

History
159 lines (118 loc) · 6.76 KB

File metadata and controls

159 lines (118 loc) · 6.76 KB

CLAUDE.md

Project guidelines for AI agents working in this codebase.

What This Is

A proxy that bridges OpenCode (Anthropic API format) to Claude Max (Agent SDK). See ARCHITECTURE.md for the full module map and dependency rules.

Commands

npm test          # Run all tests (bun test)
npm run build     # Build with tsup
npm start         # Start the proxy server

Code Rules

Module Boundaries

  • Do not add code to server.ts that belongs in a leaf module. If it's pure logic (no HTTP, no Hono), extract it.
  • session/lineage.ts must stay pure. No side effects, no I/O, no imports from cache or server.
  • Leaf modules (errors.ts, models.ts, tools.ts, messages.ts) must not import from server.ts or session/. Dependencies flow downward only.
  • No circular dependencies.

Agent-Specific Logic

OpenCode-specific behavior is documented in ARCHITECTURE.md under "Agent-Specific Logic". When modifying these areas:

  • Add a NOTE: comment marking the code as agent-specific
  • Do not spread agent-specific logic into new modules
  • Future work will use an adapter pattern — see DEFERRED.md

Testing

  • Every extracted module must have unit tests
  • Pure functions get direct unit tests (no mocks)
  • Integration tests go through the HTTP layer with mocked SDK
  • All tests must pass before any change is considered complete
  • New test files go in src/__tests__/
  • E2E tests are documented in E2E.md — run manually before releases or after major refactors (requires Claude Max subscription)

Style

  • No as any, @ts-ignore, or @ts-expect-error
  • No empty catch blocks
  • Match existing patterns — check neighboring code before writing
  • Keep server.ts as thin as possible — it should orchestrate, not compute

Architecture Quick Reference

server.ts          → HTTP routes, SSE streaming, concurrency (orchestration only)
adapter.ts         → AgentAdapter interface (extensibility point)
adapters/
  opencode.ts      → OpenCode-specific: headers, CWD, tool config
  forgecode.ts     → ForgeCode-specific: XML CWD, patch/shell tools, passthrough
query.ts           → buildQueryOptions (shared stream/non-stream SDK call builder)
errors.ts          → classifyError (pure)
models.ts          → mapModelToClaudeModel, resolveClaudeExecutableAsync
tools.ts           → BLOCKED_BUILTIN_TOOLS, CLAUDE_CODE_ONLY_TOOLS, MCP_SERVER_NAME
messages.ts        → normalizeContent, getLastUserMessage (pure)
fileChanges.ts     → PostToolUse hook: file write/edit tracking + summary formatting (pure)
session/
  lineage.ts       → Hashing, lineage verification (PURE — no I/O)
  fingerprint.ts   → extractClientCwd, getConversationFingerprint
  cache.ts         → LRU caches, lookupSession, storeSession (stateful)

Stable API Contract

External plugins depend on these interfaces. Do not change without project owner approval.

Interface Location Used by
startProxyServer(config)ProxyInstance server.ts Plugins that spawn proxy instances
ProxyInstance.close() types.ts Plugins for graceful shutdown
ProxyConfig type types.ts Plugin configuration
x-opencode-session header adapters/opencode.ts Session tracking from agent plugins
x-meridian-profile header server.ts, profiles.ts Per-request profile selection
GET /health response shape server.ts Plugin health checks
POST /v1/messages request/response format server.ts All agents (Anthropic API contract)
GET /profiles/list response shape server.ts Profile management UI and CLI
POST /profiles/active request/response server.ts Profile switching from CLI and UI

If you need to modify any of these, open an issue first — breaking changes affect downstream plugin authors.

Git & Workflow

Commit format

  • Format: type: brief description
  • Types: feat, fix, refactor, perf, test, docs, chore
  • No AI attribution lines

Development workflow — NEVER push directly to main

All changes go through this process, no exceptions:

  1. Create a feature branch from main:

    git checkout -b feat/my-feature main
  2. Make changes, commit, push the branch:

    git add -A && git commit -m "feat: my feature"
    git push origin feat/my-feature
  3. Create a PR targeting main:

    gh pr create --title "feat: my feature" --base main
  4. Wait for CI — the test job must pass before merging:

    gh pr checks <PR_NUMBER>
  5. Merge the PR (squash merge preferred):

    gh pr merge <PR_NUMBER> --squash --delete-branch
  6. Never run git push origin main directly — all code reaches main through merged PRs only.

Releasing

Do NOT run npm version, git push --tags, or npm publish manually.

Releases are handled automatically by Release Please:

  1. Merge PRs to main using Conventional Commits (feat:, fix:, etc.)
  2. Release Please auto-creates/updates a release PR that batches all unreleased changes
  3. Review the release PR — the changelog should only show changes since the last release
  4. When ready to ship, merge the release PR:
    gh pr merge <RELEASE_PR_NUMBER> --merge
  5. Merging the release PR automatically:
    • Bumps package.json and CHANGELOG.md
    • Creates a git tag (meridian-v*) and GitHub Release
    • Runs tests, builds, and publishes to npm with provenance

Multiple PRs get batched into a single release. Never publish manually.

Troubleshooting releases

  • Changelog shows entire history? — Release Please can't find the previous release tag. Check that meridian-v<version> tags exist for recent releases: git tag -l 'meridian-v*' | tail -5
  • Release PR not updating? — It only updates on push to main. If you closed it, push any commit to main to regenerate.
  • Publish failed with E403? — The version was already published. This is safe to ignore; the release is already on npm.
  • publish_only workflow dispatch — Emergency escape hatch to publish the current version without Release Please. Only use when the normal flow is broken.

Release config files

  • .release-please-manifest.json — tracks the current released version. Release Please updates this automatically when a release PR is merged. Do not edit manually unless resetting the version anchor.
  • release-please-config.json — defines the release type (node), component name, and changelog section mapping.
  • .github/workflows/release-please.yml — the workflow that runs on every push to main. It creates/updates the release PR and publishes to npm when merged.