Skip to content

feat: Auto-fallback to user scope when not in a git repo#12

Merged
gricha merged 1 commit intomainfrom
feat/auto-scope-fallback
Feb 18, 2026
Merged

feat: Auto-fallback to user scope when not in a git repo#12
gricha merged 1 commit intomainfrom
feat/auto-scope-fallback

Conversation

@gricha
Copy link
Member

@gricha gricha commented Feb 17, 2026

Previously, running any dotagents command without --user always assumed project scope, which meant commands failed with "Config file not found" when run outside a project. Users had to know about --user upfront.

Now commands intelligently resolve scope when --user is not passed:

Situation Behavior
agents.toml exists at cwd Project scope (unchanged)
Not inside any git repo Auto-fallback to user scope, prints notice
In a repo, no agents.toml Error: "Run dotagents init or use --user"
--user passed Always user scope (unchanged)

This makes dotagents add, dotagents install, etc. work from anywhere (e.g. ~/Downloads, /tmp) without requiring --user — since there's no project context, user scope is the only sensible target. When inside a repo without agents.toml, we error with a helpful message rather than silently falling back, since the user likely intended project scope and forgot to init.

Adds isInsideGitRepo() (walks up looking for .git), resolveDefaultScope(), and ScopeError to scope.ts. Each command's entry point switches from the old one-liner to flags?.user ? resolveScope("user") : resolveDefaultScope(resolve(".")). The init command uses isInsideGitRepo directly since it doesn't require an existing config.

Agent transcript: https://claudescope.sentry.dev/share/fkGkDLJxGI6t9eEm3C9vODNUwIdsQxBWkNY6YjydThg

When --user is not passed, commands now intelligently resolve scope:
- If agents.toml exists at cwd → project scope (unchanged)
- If not inside a git repo → auto-fallback to user scope with a notice
- If inside a repo but no agents.toml → error with helpful message

This makes dotagents "just work" from anywhere without requiring --user
when there's no project context. The init command uses the same logic
but without requiring an existing agents.toml.

Agent transcript: https://claudescope.sentry.dev/share/JYkkZppSemFd4LGkWjd1ajZCWFyAeXQc572EY9FFrmE
@gricha gricha marked this pull request as ready for review February 17, 2026 21:50
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

scope = resolveScope("user");
} else {
scope = resolveScope("project", resolve("."));
}
Copy link

Choose a reason for hiding this comment

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

Init scope resolution skips agents.toml existence check

Medium Severity

The init command's scope resolution logic doesn't check for agents.toml existence before falling back based on git repo detection, unlike resolveDefaultScope used by every other command. In a non-git directory that already has agents.toml (e.g., a Mercurial project, or a copied project), other commands correctly resolve to project scope, but dotagents init --force would silently target user scope instead, potentially overwriting ~/.agents/agents.toml while leaving the project config untouched.

Additional Locations (1)

Fix in Cursor Fix in Web

while (true) {
if (existsSync(join(current, ".git"))) return true;
const parent = dirname(current);
if (parent === current || parent === root) return false;
Copy link

Choose a reason for hiding this comment

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

Dead root variable in isInsideGitRepo loop termination

Low Severity

The root variable and the parent === root check in isInsideGitRepo are dead code. When root is defined (i.e., dir is the filesystem root itself), parent === current is already true on the very first iteration, so parent === root is never the deciding condition. When root is undefined (the normal case), parent === root is always false. The loop terminates correctly via parent === current alone in all cases, making the root variable misleading — it suggests a special case is being handled when it isn't.

Fix in Cursor Fix in Web

@gricha gricha merged commit 1bd5aa8 into main Feb 18, 2026
13 checks passed
@gricha gricha deleted the feat/auto-scope-fallback branch February 18, 2026 03:26
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.

1 participant