Repository navigation
Closed as not planned
Closed as not planned
Copy link
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Description:
OpenCode currently only promotes a directory from “global” to a distinct project when Git has at least one commit. This forces users to make an initial commit even when they only want project-scoped config or agents. We should treat a directory as a local project if either (a) a .git directory exists (even without commits) or (b) an opencode.json file is present at the root.
Current behavior
git initalone (no commits) →project.id === "global"1- Adding
opencode.jsondoes not affect project ID detection 2 - Tests confirm: repo with only
git inityields global; repo with commits yields non-global 3
Expected behavior
- Presence of
.gitdirectory ORopencode.jsonshould cause OpenCode to assign a non-global project ID and enable project-scoped features (e.g.,.opencode/directories, project config precedence).
Why this matters
- Users often create a project to set up agents or project-specific config before committing.
- Requiring an initial commit is unnecessary friction for configuration-only workflows.
opencode.jsonalready signals intent to be a project; it should influence project detection.
Suggested implementation hints
- In
Project.fromDirectory, after the existing Git toplevel/common-dir checks, add a fallback:- If
existsSync(path.join(directory, ".git"))ORFilesystem.findUp("opencode.json", directory)succeeds, generate a non-global project ID (e.g., hash of the absolute path) and setvcs: "git"if.gitexists, elsevcs: undefined.
- If
- Ensure
migrateFromGlobalruns for these newly-recognized projects 4 . - Update tests to cover both cases.
Acceptance criteria
- Directory with only
.git(no commits) opens as a local project. - Directory with
opencode.json(no Git) opens as a local project. - Existing behavior with committed Git repos is unchanged.
- Sessions migrate from global to the new local project when applicable.
Notes
- The UI determines “global” status by checking
projectID === "global"or when metadata lacks an ID but has local overrides 5 . - Project configs already override global configs in the merge order, but they don’t affect the initial project ID assignment 6 .
Wiki pages you might want to explore:
Citations
File: packages/opencode/src/project/project.ts (L143-192)
const top = await git(["rev-parse", "--show-toplevel"], {
cwd: sandbox,
})
.then(async (result) => path.resolve(sandbox, (await result.text()).trim()))
.catch(() => undefined)
if (!top) {
return {
id,
sandbox,
worktree: sandbox,
vcs: Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS),
}
}
sandbox = top
const worktree = await git(["rev-parse", "--git-common-dir"], {
cwd: sandbox,
})
.then(async (result) => {
const dirname = path.dirname((await result.text()).trim())
if (dirname === ".") return sandbox
return dirname
})
.catch(() => undefined)
if (!worktree) {
return {
id,
sandbox,
worktree: sandbox,
vcs: Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS),
}
}
return {
id,
sandbox,
worktree,
vcs: "git",
}
}
return {
id: "global",
worktree: "/",
sandbox: "/",
vcs: Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS),
}File: packages/opencode/src/project/project.ts (L294-314)
async function migrateFromGlobal(id: string, worktree: string) {
const row = Database.use((db) => db.select().from(ProjectTable).where(eq(ProjectTable.id, "global")).get())
if (!row) return
const sessions = Database.use((db) =>
db.select().from(SessionTable).where(eq(SessionTable.project_id, "global")).all(),
)
if (sessions.length === 0) return
log.info("migrating sessions from global", { newProjectID: id, worktree, count: sessions.length })
await work(10, sessions, async (row) => {
// Skip sessions that belong to a different directory
if (row.directory && row.directory !== worktree) return
log.info("migrating session", { sessionID: row.id, from: "global", to: id })
Database.use((db) => db.update(SessionTable).set({ project_id: id }).where(eq(SessionTable.id, row.id)).run())
}).catch((error) => {
log.error("failed to migrate sessions from global to project", { error, projectId: id })
})
}File: packages/web/src/content/docs/config.mdx (L41-52)
### Precedence order
Config sources are loaded in this order (later sources override earlier ones):
1. **Remote config** (from `.well-known/opencode`) - organizational defaults
2. **Global config** (`~/.config/opencode/opencode.json`) - user preferences
3. **Custom config** (`OPENCODE_CONFIG` env var) - custom overrides
4. **Project config** (`opencode.json` in project) - project-specific settings
5. **`.opencode` directories** - agents, commands, plugins
6. **Inline config** (`OPENCODE_CONFIG_CONTENT` env var) - runtime overrides
This means project configs can override global defaults, and global configs can override remote organizational defaults.
File: packages/web/src/content/docs/config.mdx (L104-114)
### Per project
Add `opencode.json` in your project root. Project config has the highest precedence among standard config files - it overrides both global and remote configs.
:::tip
Place project specific config in the root of your project.
:::
When OpenCode starts up, it looks for a config file in the current directory or traverse up to the nearest Git directory.
This is also safe to be checked into Git and uses the same schema as the global one.
File: packages/app/src/context/layout.tsx (L343-356)
const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
if (!isGlobal) return base
return {
...base,
id: base.id ?? "global",
name: local?.name,
commands: local?.commands,
icon: {
url: base.icon?.url,
override: local?.icon?.override,
color: local?.icon?.color,
},
}Reacted by JtMotoX
Metadata
Metadata
Assignees
Labels
No labels
Activity
diegohb commentedon Feb 26, 2026
Further context at this deepwiki chat and it also includes proposal to add cli command to convert a global project to local project on demand: https://deepwiki.com/search/how-do-i-change-a-project-of-g_3229a6c6-57fa-4bc0-9713-aa3818ca87e2?mode=fast
[-][FEATURE]: Treat directories with .git or opencode.json as local projects (not global)[/-][+][QOL]: Treat directories with .git or opencode.json as local projects (not global)[/+]JtMotoX commentedon May 5, 2026
@diegohb I really like that idea! That link seems to be dead. Any movement on that?
JtMotoX commentedon May 5, 2026
I found a workaround. If you create a
.git/opencodefile that contains a unique identifier, then restart opencode, it treats it as a local project.epicwhale commentedon Jun 18, 2026
+1 to this pain point feels like a bug that a git init isn't enough for treating a directory as a project - and ive to actually wait till making the first commit?
fix(mcp-tests): remove git-init workaround by bumping OpenCode to 1.18.1
fix(mcp-tests): remove git-init workaround by bumping OpenCode to 1.18.1
Remove git-init workaround from OpenCode CLI MCP tools harness (#142)
github-actions commentedon Aug 18, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.