Skip to content

[Feature]: Inherit a default provider and model from a parent directory (e.g. ~/Developer/Work vs ~/Developer/Personal) #6179

Description

@brzzdev

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I am describing a concrete problem or use case, not just a vague idea.

Area

apps/web

Problem or use case

My projects live in two trees that mean different things:

~/Developer/Personal/...
~/Developer/Work/...

Everything under Work should start on my work provider account and its approved model. Everything under Personal should start on my personal one. The split is a property of where the project lives, not of any individual project.

Today the default provider and model is a per-project field. defaultModelSelection already exists on the project record (packages/contracts/src/orchestration.ts:225, :424, :1086), project.meta.update accepts it (:629, :639), and draft/thread creation already consumes it. So the mechanism works — but it has to be set once per project, by hand, and again for every new project I add.

That does not scale past a handful of repos, and the failure mode is quiet: a new project under Work inherits nothing, so the first thread starts on whichever selection was last used, which may be the personal account. The mistake is usually only obvious after the turn has already run.

Proposed solution

Let a parent directory carry a default ModelSelection that projects underneath inherit.

  • In sidebar/project settings, allow setting a default provider + model on a directory scope (e.g. ~/Developer/Work), not just on a single project.
  • Resolve a project's effective default by walking its workspaceRoot up to the nearest ancestor that has a default configured; the longest matching path prefix wins, so ~/Developer/Work/client-a can still override ~/Developer/Work.
  • An explicit per-project defaultModelSelection continues to win over any inherited one.
  • New threads and drafts consume the resolved value through the path that already exists — no change to thread creation.

Path prefix matching already has a home: normalizeProjectPathForComparison and the ancestor/prefix logic in packages/client-runtime/src/state/projectGrouping.ts do this kind of comparison for the sidebar's directory grouping today.

Why this matters

It turns "keep work and personal accounts separate" from a per-project chore that silently fails on every new repo into a rule I state once. That matters for cost attribution, for subscription and rate limits landing on the right account, and for organizational boundaries where running a work repo through a personal account is a real problem rather than an inconvenience.

It is also the natural way to express the intent. I do not want to configure thirty projects; I want to say "this tree is work".

Smallest useful scope

One inherited ModelSelection per directory, resolved by longest matching path prefix, with per-project settings taking precedence.

No new grouping entity, no per-folder settings UI tree, no allow-list of permitted models, no server or provider changes. Reuse the existing defaultModelSelection contract and the existing project-settings dialog; add the directory scope and the resolution step.

Alternatives considered

Risks or tradeoffs

  • Resolution needs one clear rule. Longest matching prefix, project override wins, is the least surprising; anything fuzzier gets hard to reason about when trees nest.
  • Path comparison has to stay consistent with existing normalisation — case sensitivity, trailing separators, and Windows separators. normalizeProjectPathForComparison already handles this and should be the single source of truth rather than a second implementation.
  • Symlinked or moved projects can fall outside the tree they appear to be in. Matching on the stored workspaceRoot is predictable even if it occasionally surprises.
  • The UI needs to show why a project's default is what it is — an inherited value that looks unset is worse than no feature. Showing "inherited from ~/Developer/Work" alongside the control would cover it.

Examples or references

Relevant existing surface:

Contribution

  • I would be open to helping implement this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions