Skip to content

feat: add profile-based routing foundation#161

Open
davetha wants to merge 4 commits intorynfar:mainfrom
davetha:feature/profile-routing-foundation
Open

feat: add profile-based routing foundation#161
davetha wants to merge 4 commits intorynfar:mainfrom
davetha:feature/profile-routing-foundation

Conversation

@davetha
Copy link
Copy Markdown

@davetha davetha commented Mar 26, 2026

Summary

  • add a profile-based routing foundation so Meridian can distinguish between multiple Claude contexts instead of assuming one global account/session space
  • scope session lookup and resume by profile, and allow profile selection via x-meridian-profile
  • add a local example for running one Meridian instance with personal/company profiles on the same port

Use Case

I have both a personal and a company Claude account/plan, and I want to use OpenCode from several systems without having to install and auth Meridian separately on each machine.

The goal is to run a single Meridian instance that I can reach over my local network or a private Tailscale tunnel, then route requests to the right Claude profile from each client. That gives me better control over which systems use which account, while still feeling similar to how each machine might otherwise have its own claude auth setup.

This PR only adds the profile-routing foundation. It does not add request authentication or admin-route protection yet.

Testing

  • bun test src/__tests__/proxy-profiles.test.ts
  • bun test src/__tests__/proxy-stale-uuid-retry.test.ts
  • npm run build

Notes

Follow-up PRs will keep the maintainer review small:

  1. config file loading + optional request API keys
  2. optional protection for /health and /telemetry*

@rynfar
Copy link
Copy Markdown
Owner

rynfar commented Mar 27, 2026

I'll review this in the morning! Thank you for. the submission and ideas!

Copy link
Copy Markdown
Owner

@rynfar rynfar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Good work on this — the scope is right, the session isolation approach is clean, and the per-profile auth caching is well done. I want to merge this once two things are adjusted:

1. Move getProfileId out of AgentAdapter

x-meridian-profile is Meridian proxy infrastructure, not an agent-specific concern. Every adapter would implement it identically — it's just c.req.header("x-meridian-profile"). The AgentAdapter interface should stay focused on abstracting agent differences (OpenCode vs. future agents).

Read the header directly in server.ts instead:

const requestedProfileId = c.req.header("x-meridian-profile")
const requestedProfile = resolveProfile(finalConfig, requestedProfileId)

And drop getProfileId from adapter.ts and adapters/opencode.ts.

2. Handle unknown profile as a 400, not a 500

Right now if a client sends x-meridian-profile: nonexistent, resolveProfile() throws, which hits the generic catch in server.ts and returns a 500 with a stack trace. This should be a clean 400.

Easiest fix — catch it at the call site in server.ts:

let requestedProfile: ResolvedProfile
try {
  requestedProfile = resolveProfile(finalConfig, requestedProfileId)
} catch (e) {
  return c.json({
    type: "error",
    error: { type: "invalid_request_error", message: e instanceof Error ? e.message : "Invalid profile" },
  }, 400)
}

Everything else looks good. The buildScopedKey approach, the per-profile auth status cache, and the test coverage are all solid. Happy to merge once these two are in.

@davetha
Copy link
Copy Markdown
Author

davetha commented Mar 30, 2026

Thanks for the feedback. Whenever I get some free time I'll get the suggestions added in, and continue testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants